我的目标是将包含各种内容(大约 2 到 15 GB)的大型单个 XML 文件拆分为多个 XML 文件,每个 XML 文件都包含特定的实体类型,例如稍后可以通过 SQL 数据库导入。我目前正在使用Saxon-EE 版本 9.5.1.2J,但任何其他 XSL 处理器只要它能够快速可靠地完成这项工作就可以了。
这是我已经弄清楚的:
- Saxon似乎是 XSLT 3.0 的事实上的标准处理器,而 Raptor XML 服务器似乎是另一种(更昂贵的)选择。其他 XSL 处理器通常只支持 XSLT 1.0。
- 可以使用XSLT 3.0 流处理大文件,因此不需要将整个文件放入内存中。注意:此功能仅在 Saxon Enterprise Edition 中可用。
- 您可以使用
<xsl:result-document>
将输出写入不同的文件,但不能在同一个样式表中多次使用它来写入同一个文件(显然不是线程安全的)。 <xsl:for-each-group>
与 group-by 显然是不可流式的<xsl:stream>
只能包含一个<xsl:iterate>
块,没关系。但是:在该迭代块中,您只能访问当前节点和一个子节点的属性(甚至<xsl:for-each>
可以在该节点上工作)。如果您尝试访问第二个节点的值,则会收到“SXST0060:多个子表达式消耗输入流”错误。<xsl:apply-templates>
inside<xsl:stream>
(而不是迭代)需要模式流式处理(如下所示)。但是,与 iterate 一样,该流只能使用一次 - 否则您还会收到错误“SXST0060:多个子表达式使用输入流”。
我的结论是,当前可用的 XSL 处理器需要使用多个<xsl:stream>
标签来写入不同的文件,这实际上意味着为每个输出文件多次扫描大型输入文件。这甚至是正确的,当将不同的实体写入同一个输出文件作为一种解决方法时,因为不可能多次“使用”同一个输入流:
<xsl:mode name="s" streamable="yes"/>
<xsl:template match="/">
<xsl:stream href="input.xml">
<xsl:apply-templates mode="s" select="content/articles"/>
</xsl:stream>
<xsl:stream href="input.xml">
<xsl:apply-templates mode="s" select="content/articles/article/authors"/>
</xsl:stream>
</xsl:template>
使用解释的和更复杂的命令行脚本从大型 XML 文件中提取不同实体的速度更快——因此相比之下 XSLT 变得缓慢且无用:(
我希望有一个基于 XSLT 3.0 的解决方案可以按预期工作而无需多次扫描输入文件?我没有看到 XSLT 的基本技术限制阻止了这种用例。