xml - XML XSLT 使用 SAXON EE10.6 流式传输大型 xml 文件
问题描述
我必须将大型 xml 文件 (>5Gb) 导入 SOLR。我想先用 SAXON EE10.6 和流式 xsl 转换一个 xml 文件。我已阅读 SAXON EE10.6 应该可以,但我收到以下错误:
mytest.xsl 的第 20 行第 34 列出错:XTSE3430 模板规则不可流式传输
- 有多个消费操作数:第 21 行的 {<field {(attr{name=...}, ...)}/>} 和第 27 行的 {xsl:apply-templates}
- 模板规则的结果可以包含流式节点 模板规则不可流式
- 有多个消费操作数:第 21 行的 {<field {(attr{name=...}, ...)}/>} 和第 27 行的 {xsl:apply-templates}
- 模板规则的结果可以包含流式节点
我不熟悉流式传输 xslt 和撒克逊语。如何让我的 xslt 适合流式传输以输出所需的 Solr 添加文档 xml。
我在这里有一个简化版本的 xml 和我使用的 xslt:https ://xsltfiddle.liberty-development.net/asoTKU
它适用于较小的 xml 文件 (<1Gb)
解决方案
XSLT 3.0 流的规则非常复杂,教程介绍很少也无济于事。一个非常有用的资源是 Abel Braaksma 在 XML 布拉格 2014 上的演讲:https ://www.xfront.com/Transcript-of-Abel-Braaksma-talk-on-XSLT-Streaming- at-XML-Prague-2014.pdf
要记住的最重要的规则是:模板规则只能进行一次向下选择(它只有一次机会扫描后代树)。这就是您在编写时打破的规则:
<xsl:template match="node()">
<xsl:element name="field">
<xsl:attribute name="name">
<xsl:value-of select="local-name()"/>
</xsl:attribute>
<xsl:value-of select="."/>
</xsl:element>
<xsl:apply-templates select="*"/>
</xsl:template>
实际上,该代码可以简化为
<xsl:template match="node()">
<field name="{local-name()}">{.}</field>
<xsl:apply-templates select="*"/>
</xsl:template>
但这不会影响流能力:您正在处理匹配节点的后代两次,一次获取字符串值 (.),一次将模板应用于子节点。
现在,在我看来,这个模板规则似乎只用于处理“叶元素”,即具有文本节点子节点但没有子元素的元素。如果是这种情况,那么<xsl:apply-templates select="*"/>
永远不会选择任何东西:它是多余的并且可以被删除,这使得规则可流化。
您会收到另一条错误消息,即模板规则可以返回流式节点。不允许返回流式节点的原因有点微妙。它基本上使处理器无法进行数据流分析以证明流式传输是否可行。但这又是<xsl:apply-templates select="*"/>
问题的原因,摆脱它可以解决问题。
您的下一个问题是关于 Property 元素的模板规则。你把它写成
<xsl:template match="Property">
<xsl:element name="field">
<xsl:attribute name="name">
<xsl:value-of select="key"/>_s</xsl:attribute>
<xsl:value-of select="value"/>
</xsl:element>
<xsl:apply-templates select="Property"/>
</xsl:template>
它简化为:
<xsl:template match="Property">
<field name="{key}_s">{value}</field>
<xsl:apply-templates select="Property"/>
</xsl:template>
这将做出三个向下的选择:child::key
、child::value
和child::Property
。在您的数据样本中,没有Property
元素有一个名为 的子元素Property
,因此 可能<xsl:apply-templates/>
又是多余的。一个有用的技巧是将它们读入地图key
:value
<xsl:template match="Property">
<xsl:variable name="pair" as="map(*)">
<xsl:map>
<xsl:map-entry key="'key'" select="string(key)"/>
<xsl:map-entry key="'value'" select="string(value)"/>
</xsl:map>
</xsl:variable>
<field name="{$pair?key}_s">{$pair?value}</field>
</xsl:template>
这样做的原因是xsl:map
(like xsl:fork
) 是“一次向下选择”规则的一个例外 - 地图可以在输入的单次传递中构建。通过调用string()
,我们注意不要将任何流式节点放入地图中,因此我们稍后需要的数据已经在地图中捕获,我们不需要返回流式输入文档再次读取它.
我希望这能让您对前进的道路有所了解。XSLT 中的流式处理不适合胆小的人,但如果您有 >5Gb 的输入文档,那么您就没有太多选择了。
推荐阅读
- react-admin - 为什么我会收到“关联的参考资料似乎不再可用”?
- c# - Autofac - 注册所有派生接口及其实现
- spring - Spring Security 多次调用需要在 SecurityContext 中使用多个令牌的不同 OAuth 服务器
- go - Private struct methods
- javascript - 增加 MapboxGL.PointAnnotation 的大小
- python - Tensorflow ValueError:logits和标签必须具有相同的形状((None,2)vs(None,1))
- c++ - 运算符“”在 C++ 中做了什么?
- laravel - 为 laravel 应用程序将包更新应用到 ubuntu
- javascript - 使用 Jasmine 在 Angular 中测试异步函数的问题
- c++ - 如何让 C++ 从 lambda 推断模板类型参数?