在 java 中解析非常大的 XML 文档(以及更多)

Posted

技术标签:

【中文标题】在 java 中解析非常大的 XML 文档(以及更多)【英文标题】:Parsing very large XML documents (and a bit more) in java 【发布时间】:2010-09-26 05:39:04 【问题描述】:

(以下全部用Java编写)

我必须构建一个将可能非常大的 XML 文档作为输入的应用程序。该文档是加密的——不是使用 XMLsec,而是使用我的客户预先存在的加密算法——将分三个阶段进行处理:

首先,将根据上述算法对流进行解密。

其次,扩展类(由第三方编写到我提供的 API)将读取文件的某些部分。读取的数量是不可预测的——特别是它不能保证在文件的标题中,但可能发生在 XML 中的任何位置。

最后,另一个扩展类(同样处理)将输入 XML 细分为 1..n 个子集文档。这些可能会在某些部分与第二个操作处理的文档部分重叠,即:我相信我需要回退我用来处理这个对象的任何机制。

这是我的问题:

有没有一种方法可以做到这一点,而无需一次将整个数据读入内存?显然我可以将解密实现为输入流过滤器,但我不确定是否可以按照我描述的方式解析 XML;通过遍历尽可能多的文档以收集第二步的信息,然后通过倒回文档并再次将其传递以将其拆分为作业,理想情况下释放文档中不再使用的所有部分他们已经通过了。

【问题讨论】:

【参考方案1】:

查看XOM 库。您正在寻找的示例是源代码分发的示例目录中的StreamingExampleExtractor.java。这显示了一种对大型 xml 文档执行流式解析的技术,它只构建特定节点、处理它们并丢弃它们。它与 sax 方法非常相似,但内置了更多解析功能,因此可以很容易地实现流解析。

如果您想在更高级别工作,请查看NUX。这提供了一个高级流式 xpath API,它只将评估 xpath 所需的数据量读入内存。

【讨论】:

【参考方案2】:

我会编写一个InputStream 的自定义实现,它会解密文件中的字节,然后使用 SAX 来解析从流中出来的结果 XML。

SAXParserFactory.newInstance().newSAXParser().parse(
  new DecryptingInputStream(), 
  new MyHandler()
);

【讨论】:

【参考方案3】:

Stax 是正确的方法。我建议查看Woodstox

【讨论】:

【参考方案4】:

这听起来像是 StAX (JSR 173) 的工作。 StAX 是一个拉式解析器,这意味着它的工作方式或多或少类似于 SAX 等基于事件的解析器,但是您可以更好地控制何时停止读取、拉取哪些元素……

此解决方案的可用性在很大程度上取决于您的扩展类实际在做什么,您是否可以控制它们的实现等等...

主要的一点是,如果文档非常大,您可能希望使用基于事件的解析器而不是基于树的解析器,因此不会占用大量内存。

可以从 SUN (SJSXP)、Codehaus 或其他一些提供商处找到 StAX 的实现。

【讨论】:

这看起来很有希望,只要我能有效地融入它。看起来我必须向我的 API 客户端公开 StAX,这不太理想,但至少看起来功能在那里。你能用推荐的实现而不是列表来修改你的帖子吗? 我知道这是一个旧的答案/评论,但有一些库可以在 stax 之上增加更多便利(并隔离一些较低级别的细节),例如 StaxMate [staxmate.codehaus.org/Tutorial]。这仍然允许增量解析/写入,但减少了要编写的代码量。【参考方案5】:

您可能对XOM感兴趣:

XOM 相当独特,因为它是 双流/基于树的 API。 树中的单个节点可以是 在文档静止时处理 正在建设。启用 XOM 程序 运行速度几乎与 底层解析器可以提供数据。你 无需等待文件 在你可以之前被完全解析 开始使用它。

XOM 非常节省内存。如果你 将整个文档读入内存, XOM 使用尽可能少的内存。 更重要的是,XOM 允许您 过滤文档,因为它们是这样构建的 您不必构建 你不感兴趣的树。对于 例如,您可以跳过构建文本 仅代表边界的节点 空白,如果这样的空白是 在您的应用程序中并不重要。 您甚至可以处理文档片段 一块一块扔掉 当你完成它时。 XOM 已经 用于处理文件 千兆字节。

【讨论】:

这看起来像是一种有趣且可能有用的方法,但在文档中没有任何地方建议以您描述的方式控制文档解析的方法。我相信您它可以,但该功能没有以合理发现的方式记录。【参考方案6】:

您可以使用具有非常大缓冲区大小的BufferedInputStream,并在扩展类工作之前使用mark(),之后使用reset()

如果扩展类需要的部分在文件中很远,那么这可能会变得非常占用内存,'虽然。

更通用的解决方案是编写您自己的BufferedInputStream-workalike,如果要缓冲的数据超过某个预设阈值,它会缓冲到磁盘。

【讨论】:

以上是关于在 java 中解析非常大的 XML 文档(以及更多)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中解析非常大的 XML 文件? [复制]

在 php 中解析非常大的 XML 文件

在Java中使用xpath对xml解析

浅谈用java解析xml文档

XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式?

Powershell 中非常大的 XML 文件