什么是在Java中计算xml节点的最有效方法

时间:2010-07-20 10:49:45

标签: java xml

我有一个高达1-2gb的巨大XML文件,显然我不能一次解析整个文件,我必须将它分成几部分然后解析部分并对它们做任何事情。

如何计算某个节点的编号?所以我可以跟踪分割文件需要多少部分。有没有更好的方法来做到这一点?我愿意接受所有建议,谢谢

问题更新:

我确实使用过STAX,也许我使用它的逻辑是错误的,我正在解析文件,然后为每个节点我获取节点值并将其存储在字符串构建器中。然后在另一种方法中,我通过stringbuilder并编辑输出。然后我将该输出写入文件。我不能做这样的10000个对象。

以下是我得到的例外情况:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at com.sun.org.apache.xerces.internal.util.NamespaceSupport.<init>(Unkno
wn Source)
        at com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.setNamespace
Context(Unknown Source)
        at com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.getXMLEvent(
Unknown Source)
        at com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.allocate(Unk
nown Source)
        at com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(Unknown Sour
ce)
        at com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX.bridge(Unk
nown Source)
        at com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX.parse(Unkn
own Source)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transfor
mIdentity(Unknown Source)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transfor
m(Unknown Source)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transfor
m(Unknown Source)

实际上我认为我的整个方法都是错误的,我实际上正在尝试将xml文件转换为CSV样本。到目前为止我是这样做的:

  • 读取/解析xml文件
  • 为每个元素节点获取文本节点值
  • 打开流将其写入文件(temp),对于n个节点,然后刷新并关闭流
  • 然后打开从temp读取的另一个流,使用commons strip utils和其他一些东西创建正确的csv输出然后将其写入csv文件

8 个答案:

答案 0 :(得分:5)

SAX或STAX API是您最好的选择。他们不会立即解析整个事情,他们一次占用一个节点并让您的应用程序处理它。它们适用于任意大的文件。

SAX是较旧的API,适用于推模型,STAX更新,是拉解析器,因此更容易使用,但是根据您的要求,任何一个都可以。

请参阅this tutorial以开始使用STAX解析。

答案 1 :(得分:2)

您可以使用StAX之类的流解析器。这不需要您一次读取内存中的整个文件。

答案 2 :(得分:1)

我认为您希望避免创建DOM,因此SAXStAX应该是不错的选择。

使用SAX只需实现一个simlpe内容处理程序,只要找到一个有趣的元素,它就会增加一个计数器。

答案 3 :(得分:1)

使用SAX,您不必拆分文件:它是流式传输,因此它只保存内存中的当前位。编写一个只进行计数的ContentHandler非常容易。它的速度非常快(根据我的经验,几乎和读取文件一样快)。

答案 4 :(得分:1)

  

我确实使用过STAX,也许我使用它的逻辑是错误的,我正在解析文件,然后为每个节点我获取节点值并将其存储在字符串构建器中。然后在另一种方法中,我通过stringbuilder并编辑输出。然后我将该输出写入文件。我不能做这样的10000个对象。

通过这种描述,我会说是的,你使用它的逻辑是错误的。你内存太多了。

不是解析整个文件,将所有节点值存储到某个东西然后处理结果,而是应该在点击它时处理每个节点,并在解析时输出。

有关您实际尝试完成的内容以及输入XML和输出内容的更多详细信息,我们可能有助于简化。

答案 5 :(得分:0)

最好使用基于事件的解析器,例如SAX

答案 6 :(得分:0)

我认为拆分文件不是可行的方法。您最好将xml文件作为流处理并使用SAX API(而不是DOM API)。

更好的是,您应该使用XQuery来处理您的请求。

Saxon是一个很好的Java / .Net实现(使用sax),即使在大文件上也非常快。版本HE属于MPL开源许可证。

这是一个小例子:

java -cp saxon9he.jar net.sf.saxon.Query -qs:"count(doc('/path/to/your/doc/doc.xml')//YouTagToCount)"

答案 7 :(得分:0)

使用扩展的vtd-xml,您可以在内存中高效加载文档,因为它支持内存映射。与DOM相比,内存使用量不会在一个数量级上爆炸。并且您将能够使用xpath非常容易地计算节点数。