是否可以在 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 个文件在播放:
site.xml
:
- 此文件包含代表整个组织的数据:用户、角色、凭据、设置……
- 它可以轻松包含 10.000 行。
- 可以算作static/immutable.
- 你可以将它比作 XML 数据库的表示,可以这么说。
request.xml
:
- 此文件包含提供给 REST 的请求 API。
- 它很小,通常在 10 到 50 行左右。
- 每个请求都不一样。
request.xslt
:
- 此文件包含将给定
request.xml
转换为输出 XML. 的样式表
- 它通过 XSLT
document()
函数加载 site.xml
,因为它需要该数据来满足请求。
这里的问题是在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()
每次需要 运行 代码时创建一个 XsltTransformer
或 Xslt30Transformer
。
关于共享文档,请参阅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
定义是可共享的,如果它的 match
和 use
属性不依赖于从一个转换到另一个转换的任何变化,例如全局变量或参数的内容。
Saxon 的本机树实现(与 DOM 不同)是线程安全的:如果一次构建文档,就可以在多个线程中访问它。支持 key() 函数的索引构建是同步的,因此并发转换不会相互干扰。
Martin 关于允许对 document() 调用进行编译时评估的建议也可行。您还可以将文档放入一个用 static="yes" 定义的全局变量中。但是,将编译后的样式表导出到持久文件时效果不佳:导出包含节点值静态变量的样式表时存在一些限制。
我目前正在评估 XSLT3 with Saxon 是否对我们的目的有用。请听我说完。
我们正在开发 REST API,它在给定输入请求 XML 的情况下提供凭据。基本上,有 3 个文件在播放:
site.xml
:- 此文件包含代表整个组织的数据:用户、角色、凭据、设置……
- 它可以轻松包含 10.000 行。
- 可以算作static/immutable.
- 你可以将它比作 XML 数据库的表示,可以这么说。
request.xml
:- 此文件包含提供给 REST 的请求 API。
- 它很小,通常在 10 到 50 行左右。
- 每个请求都不一样。
request.xslt
:- 此文件包含将给定
request.xml
转换为输出 XML. 的样式表
- 它通过 XSLT
document()
函数加载site.xml
,因为它需要该数据来满足请求。
- 此文件包含将给定
这里的问题是在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()
每次需要 运行 代码时创建一个 XsltTransformer
或 Xslt30Transformer
。
关于共享文档,请参阅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
定义是可共享的,如果它的 match
和 use
属性不依赖于从一个转换到另一个转换的任何变化,例如全局变量或参数的内容。
Saxon 的本机树实现(与 DOM 不同)是线程安全的:如果一次构建文档,就可以在多个线程中访问它。支持 key() 函数的索引构建是同步的,因此并发转换不会相互干扰。
Martin 关于允许对 document() 调用进行编译时评估的建议也可行。您还可以将文档放入一个用 static="yes" 定义的全局变量中。但是,将编译后的样式表导出到持久文件时效果不佳:导出包含节点值静态变量的样式表时存在一些限制。