2008-12-10 72 views
18

(以下所有的是用Java写的)解析非常大的XML文档(多一点)在Java中

我必须建立一个将作为输入的XML文档,潜在的应用程序,很大。该文件是加密的 - 不是XMLsec,但我的客户的预先存在的加密算法 - 将分三个阶段进行处理:

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

其次,扩展类(由第三方对我提供了一个API编写)将读取该文件的某些部分。读取的数量不可预测 - 特别是不能保证位于文件头部,但可能出现在XML中的任何位置。

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

这里是我的问题:

有没有办法做到这一点没有在同一时间去阅读整片数据到内存?很明显,我可以将解密作为输入流过滤器来实现,但我不确定是否可以按照我描述的方式解析XML;通过遍历文档需要收集第二步的信息,然后通过倒回文档并再次传递以将其分割成作业,理想地释放文档中不再使用的所有部分之后他们已经通过了。

回答

3

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

如果扩展类需要很远到文件的部分,那么这可能会变得非常内存密集型,“虽然。

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

1

你可能会XOM感兴趣:

XOM是,它是一个 双码流/基于树的API相当独特。 在构建文档时仍然可以处理 树中的单个节点。使XOM程序 的运行速度几乎与底层解析器可提供数据的 一样快。你 不需要等待文件 被完全解析,然后你可以 开始使用它。

XOM的内存效率非常高。如果 将整个文档读入内存,则 XOM尽可能少地使用内存。 更重要的是,XOM允许您在创建过滤文档时使用 ,因此您无需构建您不感兴趣的树的部分 。对于 实例,可以跳过构建文本 只代表边界 空白的节点,如果这样的空白区域是 在您的应用程序中不重要。 您甚至可以逐件处理文件 ,并在完成后丢弃每件 。 XOM已被 用于处理大小为012 GB的数据。

+1

这看起来像一个有趣的,潜在有用的方法,但无处 文档有没有暗示的方式来控制你所描述的方式 文档的解析。我相信你可以这样做,但是 的功能没有以合理的方式记录下来。 – 2008-12-10 14:05:22

7

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

这个可用性解决方案将取决于你的扩展类实际在做什么,如果你有他们的实施控制等等......

重点是如果文档非常大,你可能想要使用基于事件解析器而不是基于树的,所以你不会使用大量的内存。

StAX的实现可以从SUN(SJSXP),Codehaus或几个其他供应商处找到。

+0

这看起来很有前途,只要我能有效地接触它。看起来我必须将StAX公开给我的API客户端,这并不理想,但至少它看起来像那些功能。你可以修改你的文章推荐实施,而不是清单? – 2008-12-10 15:41:25

3

我会写的InputStream定制实现,解密文件中的字节,然后使用SAX因为它涉及的料流解析生成的XML。

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

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

如果你想在更高层次上工作,请看NUX。这提供了一个高层次的流xpath API,它只能读取评估xpath所需的数据量到内存中。