10

输入文件包含数千个 XML 格式的交易,大小约为 10GB。要求是根据用户输入选择每个事务 XML 并将其发送到处理系统。

文件示例内容

<transactions>
    <txn id="1">
      <name> product 1</name>
      <price>29.99</price>
    </txn>

    <txn id="2">
      <name> product 2</name>
      <price>59.59</price>
    </txn>
</transactions>

(技术)用户应提供输入标签名称,如<txn>.

我们希望提供这个解决方案更通用。文件内容可能不同,用户可以给出一个 XPath 表达式,如 " //transactions/txn" 来选择单个事务。

在这里我们需要考虑的技术问题很少

  • 该文件可以位于共享位置或 FTP
  • 由于文件很大,我们无法在 JVM 中加载整个文件

我们可以在这种情况下使用 StAX 解析器吗?它必须将 XPath 表达式作为输入并选择/选择事务 XML。

寻找建议。提前致谢。

4

7 回答 7

16

如果性能是一个重要因素,和/或文档大小很大(这里似乎都是这种情况),那么事件解析器(如 SAX 或 StAX)与本机 Java XPath 实现之间的区别在于后者构建评估 XPath 表达式之前的 W3C DOM 文档。[有趣的是,所有 Java 文档对象模型实现,如 DOM 或 Axiom 都使用事件处理器(如 SAX 或 StAX)来构建内存表示,所以如果你只使用事件处理器就可以了节省内存和构建 DOM 所需的时间。]

正如我所提到的,JDK 中的 XPath 实现在 W3C DOM 文档上运行。您可以通过查看 Java JDK 源代码实现来看到这一点com.sun.org.apache.xpath.internal.jaxp.XPathImpl,其中在调用 evaluate() 方法之前,解析器必须首先解析源代码:

  Document document = getParser().parse( source );

在此之后,您的 10GB XML 将在内存中表示(加上任何开销)——可能不是您想要的。虽然您可能想要一个更“通用”的解决方案,但您的示例 XPath 和您的 XML 标记看起来都相对简单,因此 XPath 似乎没有一个真正强有力的理由(除了编程优雅之外)。XProc 建议也是如此:这也将构建一个 DOM。如果你真的需要一个 DOM,你可以使用 Axiom 而不是 W3C DOM。Axiom 有一个更友好的 API,并且在 StAX 上构建它的 DOM,所以它速度很快,并且使用 Jaxen 来实现它的 XPath。Jaxen 需要一些一种 DOM(W3C DOM、DOM4J 或 JDOM)。这对于所有 XPath 实现都是正确的,因此如果您并不真正需要 XPath,建议您只使用事件解析器。

SAX 是旧的流式 API,StAX 较新,速度要快得多。无论是使用本机 JDK StAX 实现 ( javax.xml.stream) 还是Woodstox StAX 实现(根据我的经验,这明显更快),我建议创建一个 XML 事件过滤器,它首先匹配元素类型名称(以捕获您的<txn>元素)。这将创建少量事件(元素、属性、文本),可以检查匹配的用户值。在合适的匹配上,如果您发现结果更易于导航,您可以从事件中提取必要的信息或通过管道传输有界事件以从中构建迷你 DOM。但如果标记很简单,这听起来可能有点矫枉过正。

这可能是最简单、最快的方法,并且避免了构建 DOM 的内存开销。如果您将元素和属性的名称传递给过滤器(以便您的匹配算法是可配置的),您可以使其相对通用。

于 2013-04-03T10:26:53.497 回答
13

Stax 和 xpath 是非常不同的东西。Stax 仅允许您向前解析流式 XML 文档。Xpath 允许双向解析。Stax 是一个非常快速的流式 XML 解析器,但是,如果你想要 xpath,java 有一个单独的库。

看一看这个问题的一个非常相似的讨论:SAX 模型是否有任何 XPath 处理器?

于 2011-08-27T17:02:45.750 回答
2

我们定期使用 SAX 解析器解析 1GB+ 复杂的 XML 文件,它完全按照您的描述:它提取可以使用 XPATH 方便地查询的部分 DOM 树。

我在这里写了一篇博客——它使用的是 SAX 而不是 StAX 解析器,但可能值得一看。

于 2012-01-07T15:36:50.330 回答
1

这绝对是 XProc 的一个用例,具有流式处理和并行处理实现,如 QuiXProc ( http://code.google.com/p/quixproc )

在这种情况下,您将不得不使用

  <p:for-each>
    <p:iteration-source select="//transactions/txn"/>
    <!-- you processing on a small file -->
  </p:for-each>

您甚至可以用一行 XProc 包装每个生成的转换

  <p:wrap-sequence wrapper="transactions"/>

希望这可以帮助

于 2011-09-03T07:04:51.960 回答
1

处理大于 10GB 的大型 XML 文件的有趣解决方案。

  1. 使用 ANTLR 为感兴趣的部分创建字节偏移。与基于 DOM 的方法相比,这将节省一些内存。
  2. 使用 Jaxb 从字节位置读取部分

在此 SO 答案https://stackoverflow.com/a/43367629/1485527中的 wikipedia dumps (17GB) 示例中查找详细信息

于 2018-02-26T09:43:05.060 回答
0

XML (STX) 的流转换可能是您需要的。

于 2011-08-27T17:21:02.603 回答
0

您需要快速处理它还是需要快速查找数据?这些要求需要不同的方法。

为了快速读取整个数据,StAX 就可以了。

如果您需要快速查找而不是将其加载到某个数据库,例如 Berkeley DB XML

于 2011-08-27T19:28:35.193 回答