是否可以在 Saxon 中缓存 XML 文档以避免重新解析和重新索引?

Is it possible to cache XML documents in Saxon to avoid re-parsing and re-indexing?

我目前正在评估 XSLT3 with Saxon 是否对我们的目的有用。请听我说完。

我们正在开发 REST API,它在给定输入请求 XML 的情况下提供凭据。基本上,有 3 个文件在播放:

这里的问题是在request.xslt中加载site.xml需要很长时间。此外,对于每个请求,必须重建 XSLT <xsl:key .../> 指令引入的索引。这加起来。

因此以某种方式缓存 site.xml 是有意义的,以避免必须为每个请求解析和索引该文件。

重要的是要注意多个 API 请求可以同时发生,因此在几个正在进行的 XSLT 转换之间共享这个缓存 site.xml 应该是安全的。

Saxon (Java) 可以吗?那将如何运作?

更新 1

经过一些额外的思考,我意识到也许我不应该尝试只缓存 site.xml XML 文件,而应该缓存 request.xslt 文件?这假设通过 document() 加载到 request.xslt 中的 site.xml 是该缓存的一部分。

如果您 show/tell 我们 API 用于 运行 XSLT with Saxon,那将会有所帮助。

至于使用 JAXP 缓存 XSLT,我认为您每次都可以使用 TransformerFactoryImpl (http://saxonica.com/html/documentation/using-xsl/embedding/jaxp-transformation.html) 中的 newTemplates 创建的 Templates 来做到这一点您想要 运行 XSLT,您将使用 newTransformer().

创建 Transformer

使用 s9api API 你可以编译一次得到一个 XsltExecutable (http://saxonica.com/html/documentation/javadoc/net/sf/saxon/s9api/XsltExecutable.html) 那 "is immutable, and therefore thread-safe", 然后你必须 load()load30() 每次需要 运行 代码时创建一个 XsltTransformerXslt30Transformer

关于共享文档,请参阅http://saxonica.com/html/documentation/sourcedocs/preloading.html:

An option is available (Feature.PRE_EVALUATE_DOC_FUNCTION) to indicate that calls to the doc() or document() functions with constant string arguments should be evaluated when a query or stylesheet is compiled, rather than at run-time. This option is intended for use when a reference or lookup document is used by all queries and transformations

然而,关于该配置选项的部分指出:

In XSLT 3.0 a better way of having external documents pre-loaded at stylesheet compile time is to use the new facility of static global variables.

所以在那种情况下你可以声明

<xsl:variable name="site-doc" static="yes" select="doc('site.xml')"/>

您需要等待 Michael Kay 的回复,看看是否足以共享文档。

嗯,这当然是可能的,但最好的方法在一定程度上取决于具体情况,例如site.xml 改变时会发生什么。

我倾向于在应用程序启动时创建单个 s9api 处理器,并立即(即在应用程序初始化期间)使用 Processor.DocumentBuilder.build() 将 site.xml 加载到 XdmNode 中;然后可以将其作为参数值(<xsl:param>)传递到使用它的每个转换中。或者,如果您更喜欢使用 document() 访问它,您可以注册一个 URIResolver,它通过返回相关的 XdmNode.

来响应 document() 调用

至于索引和key()函数,只要xsl:key定义是"sharable",那么如果基于同一个编译样式表(s9api XsltExecutable) 访问同一个文档,不会重建索引。 xsl:key 定义是可共享的,如果它的 matchuse 属性不依赖于从一个转换到另一个转换的任何变化,例如全局变量或参数的内容。

Saxon 的本机树实现(与 DOM 不同)是线程安全的:如果一次构建文档,就可以在多个线程中访问它。支持 key() 函数的索引构建是同步的,因此并发转换不会相互干扰。

Martin 关于允许对 document() 调用进行编译时评估的建议也可行。您还可以将文档放入一个用 static="yes" 定义的全局变量中。但是,将编译后的样式表导出到持久文件时效果不佳:导出包含节点值静态变量的样式表时存在一些限制。