代码之家  ›  专栏  ›  技术社区  ›  ant

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

  •  3
  • ant  · 技术社区  · 14 年前

    我有一个高达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 回复  |  直到 8 年前
        1
  •  5
  •   skaffman    14 年前

    SAX或STAX API将是您最好的选择。他们不会一次分析整个事件,他们一次只分析一个节点,让你的应用程序处理它。它们适用于任意大的文档。

    SAX是较旧的API,在推模型上工作,STAX是较新的,是一个pull解析器,因此更容易使用,但是对于您的需求,任何一个都可以。

    this tutorial 为了让您开始分析stax。

        2
  •  2
  •   Gerco Dries    14 年前

    您可以使用类似 StAX 为此。这不需要您一次读取内存中的整个文件。

        3
  •  1
  •   Andreas Dolk    14 年前

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

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

        4
  •  1
  •   Chris Lercher    14 年前

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

        5
  •  1
  •   Don Roby    14 年前

    我确实使用了stax,可能我使用它的逻辑是错误的,我在分析文件,然后为每个节点获取节点值并将其存储在字符串生成器中。然后在另一个方法中,我通过StringBuilder来编辑输出。然后我将输出写入文件。我只能做10000件这样的东西。

    根据这个描述,我会说是的,你使用它的逻辑是错误的。你的记忆力太强了。

    与其解析整个文件,将所有节点值存储到某个对象中,然后处理结果,不如在命中每个节点时对其进行处理,并在解析时输出。

    有了更多关于您实际尝试完成什么、输入XML和输出什么样的细节,我们可能会帮助简化。

        6
  •  0
  •   spender    14 年前

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

        7
  •  0
  •   alci    14 年前

    我认为拆分文件不是一种方法。您最好将XML文件作为流处理,并使用SAX API(而不是DOM API)。

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

    SAXON是一个很好的Java/.NET实现(使用SAX),这是惊人的快,甚至在大文件上。版本他在MPL开源许可证下。

    下面是一个小例子:

    java -cp saxon9he.jar net.sf.saxon.Query -qs:"count(doc('/path/to/your/doc/doc.xml')//YouTagToCount)"
    
        8
  •  0
  •   vtd-xml-author    8 年前

    使用扩展的VTD XML,您可以高效地在内存中加载文档,因为它支持内存映射。与DOM相比,内存使用不会以数量级激增。您将能够非常容易地使用xpath来计算节点的数量。