28

我有一个非常大的 XML 文件,我需要将它转换成另一个 XML 文件,我想用 XSLT 来做这件事。我对内存优化更感兴趣,而不是速度优化(不过,速度也会很好!)。

对于这项任务,您会推荐哪种基于 Java 的 XSLT 处理器?

您会推荐任何其他方式(非 XSLT?、非 Java?),如果是,为什么?

问题中的 XML 文件非常大,但不是很深 - 有数百万行(元素),但只有大约 3 级深。

4

3 回答 3

34

目前已知只有三个XSLT 2.0处理器,其中Saxon 9.x在速度和内存利用率方面可能是最有效的(至少根据我的经验)。Saxon-SA(Saxon 的模式感知版本,不像 B(基本)版本那样免费)具有流处理的特殊扩展。

从现有的各种 XSLT 1.0处理器来看,.NET XslCompiledTransform(基于 C#,而不是 Java!)似乎是冠军。

在 XSLT 1.0 处理器的基于 Java 的世界中, Saxon 6.x再次相当不错。

更新

现在,从最初回答这个问题之日起 3 年多,没有任何证据表明提到的 XSLT 处理器之间的效率差异已经改变。

至于流媒体

  1. 即使没有任何流式处理,也可以很好地处理具有“数百万个节点”的 XML 文档。我进行了一个实验,其中 Saxom 9.1.07 处理了一个 XML 文档,该文档包含大约一百万个具有整数值的 3 级元素。转换只是计算它们的总和。在我的电脑上转换的总时间不到 1.5 秒。使用的内存是 500MB——这是 10 年前个人电脑可能拥有的内存,

以下是 Saxon 的信息性消息,其中显示了有关转换的详细信息:

Saxon 9.1.0.7J from Saxonica
Java version 1.6.0_17
Stylesheet compilation time: 190 milliseconds
Processing file:/C:\temp\delete\MRowst.xml
Building tree for file:/C:\temp\delete\MRowst.xml using class net.sf.saxon.tinytree.TinyBuilder
Tree built in 1053 milliseconds
Tree size: 3075004 nodes, 1800000 characters, 0 attributes
Loading net.sf.saxon.event.MessageEmitter
Execution time: 1448 milliseconds
Memory used: 506661648
NamePool contents: 14 entries in 14 chains. 6 prefixes, 6 URIs
  1. Saxon 9.4 有一个saxon:stream() 扩展函数,可用于处理巨大的 XML 文档。

这是文档的摘录

在 Saxon 中进行流式传输基本上有两种方式:

突发模式流式传输:使用这种方法,大文件的转换被分解为文件小片段的一系列转换。每个片段依次从输入中读取,在内存中变成一棵小树,转换并写入输出文件。

这种方法适用于结构相当平坦的文件,例如保存数百万条日志记录的日志文件,其中每个日志记录的处理独立于之前的日志记录。

该技术的一个变体使用新的 XSLT 3.0 xsl:iterate 指令来迭代记录,而不是 xsl:for-each。这允许在处理记录时维护工作数据:例如,这使得在运行结束时输出总计或平均值成为可能,或者使一条记录的处理取决于文件中之前的内容. xsl:iterate 指令还允许提前退出循环,这使得转换可以从大文件的开头处理数据,而无需实际读取整个文件。

突发模式流在 XSLT 和 XQuery 中都可用,但在 XQuery 中没有与 xsl:iterate 构造等效的东西。

流式模板:这种方法遵循传统的 XSLT 处理模式,即通过将模板规则与每一层的节点匹配来执行输入 XML 层次结构的递归下降,但一次只执行一个元素,而无需在内存中构建树。

每个模板都属于一种模式(可能是默认的、未命名的模式),并且流是可以使用新的 xsl:mode 声明指定的模式的属性。如果该模式被声明为可流式传输,则该模式内的每个模板规则都必须遵守可流式处理的规则。

流处理中允许的规则非常复杂,但基本原则是给定节点的模板规则只能按顺序读取该节点的后代一次。在当前的 Saxon 实现中,还有一些限制强加的规则:例如,虽然分组 using 在理论上与流式实现是一致的,但目前在 Saxon 中没有实现。

  1. XSLT 3.0将具有标准流功能。然而,W3C 文档仍处于“工作草案”状态,流式规范在后续草案版本中可能会发生变化。因此,不存在当前草案(流式传输)规范的实现。

  2. 警告:并非所有转换都可以在流模式下执行——无论 XSLT 处理器如何。对于大型文档,无法在流模式(RAM 数量有限)中执行的转换的一个示例是对它们的元素进行排序(例如通过公共属性)。

于 2009-01-20T15:03:46.563 回答
9

您可以考虑STX,其 Java 实现是Joost。由于它类似于 XSLT,但作为一个流处理器,它能够使用非常少的 RAM 处理大量文件。

Joost 可以用作标准 javax.xml.transform.TransformerFactory

于 2009-01-20T11:32:31.077 回答
4

请参阅 Saxon 对流模式的支持。http://www.saxonica.com/html/documentation/sourcedocs/streaming/

如果这种流模式不适合您,您可以尝试使用Saxon 的小树模式,该模式针对较小的内存使用进行了优化。(无论如何都是默认的)

于 2009-01-20T11:30:23.330 回答