【问题标题】:Parsing very large XML files and marshalling to Java Objects解析非常大的 XML 文件并编组为 Java 对象
【发布时间】:2011-10-12 21:39:32
【问题描述】:

我有以下问题:我有非常大的 XML 文件(如 300+ Megs),我需要解析它们以便将它们的一些值添加到 db。这些文件的结构也很复杂。我想使用 Stax Parser,因为它提供了一次拉解析(并因此处理)XML 文件的一部分的很好的可能性,因此不会将整个内容加载到内存中,而是另一方面获取值Stax(至少在这些 XML 文件上)很麻烦,我需要编写大量代码。从后一种角度来看,如果我可以将 XML 文件编组为 Java 对象(就像 JAX-B 一样),它将极大地帮助我,但这会同时加载整个文件以及内存中的大量 Object 实例。

我的问题是,是否有某种方法可以按顺序提取解析(或仅部分解析)文件,然后仅将这些部分编组为 Java 对象,以便我可以轻松处理它们而不会占用内存?

【问题讨论】:

    标签: java xml


    【解决方案1】:

    我会推荐 Eclipse EMF。但它有同样的问题,如果你给它文件名,它会解析整个事情。虽然有一些选项可以减少加载量,但我并没有太在意,因为我们在具有 96 GB RAM 的机器上运行。 :)

    无论如何,如果您的 XML 格式定义良好,那么一种解决方法是通过将整个文件分解为几个较小(但仍然定义良好)的 XML sn-ps 来欺骗 EMF。然后一个接一个地喂每个 sn-p。我不知道 JAX-B,但也许同样的解决方法也可以在那里应用。我会推荐,因为 EMF 对于这样一个小问题来说太大了。

    如果您的 XML 看起来像这样,请稍微详细说明一下:

    <tag1>
        <tag2>
            <tag3/>
            <tag4>
                <tag5/>
            </tag4>
            <tag6/>
            <tag7/>
        </tag2>
    
        <tag2>
            <tag3/>
            <tag4>
                <tag5/>
            </tag4>
            <tag6/>
            <tag7/>
        </tag2>
    ............
        <tag2>
            <tag3/>
            <tag4>
                <tag5/>
            </tag4>
            <tag6/>
            <tag7/>
        </tag2>
    </tag1>
    

    然后可以将其分解为一个 XML,每个 XML 以 &lt;tag2&gt; 开头并以 &lt;/tag2&gt; 结尾。而在 java 中,大多数解析器都会接受 Stream,因此只需使用您想要的任何内容进行解析,在循环中为每个 &lt;tag2&gt; 创建一些 StringStream 或其他内容,然后传递给 JAX-B 或 EMF。

    HTH

    【讨论】:

    • 这听起来很棒,我明天会首先尝试(现在是午夜 :))。感谢您的建议,听起来很有希望
    • @thekashyap。请问我可以拥有其中一台机器吗?只有一个!
    • 呵呵..这些是我们的测试机,我在家里用一台 4GB 的 Win7 笔记本电脑和其他人一样.. :)
    【解决方案2】:

    嗯,首先我要感谢回答我问题的两个人,但我最终没有使用这些提议,部分原因是这些提议的技术离 Java 有点远,比如说“标准 XML 解析”,感觉很奇怪到目前为止,Java 中已经存在类似的工具,部分原因是事实上我确实找到了一个仅使用 Java API 来完成此任务的解决方案。

    我不会详细介绍我找到的解决方案,因为我已经完成了实现,而且这里放置了相当多的代码(我在这一切之上使用 Spring Batch,并进行了大量配置和东西)。

    不过,我将对我最终完成的工作发表一点评论:

    这里的主要想法是,如果您有一个 XML 文档并且它是相应的 XSD 模式,您可以使用 JAXB 对其进行解析和编组,并且可以分块进行,并且可以使用偶数解析器读取所述块例如 STAX,然后传递给 JAXB Marshaller。

    这实际上意味着您必须首先确定您的 XML 文件中的一个好位置,您可以说“这里的这部分有很多重复结构,我将一次处理这些重复”。这些重复部分通常是在父标签内重复很多次的相同(子)标签。因此,您所要做的就是在您的 STAX 解析器中创建一个事件侦听器,该事件侦听器在每个子标签的开头触发,然后将该子标签的内容流式传输到 JAXB,使用 JAXB 编组并处理它。

    这个想法在我遵循的这篇文章中得到了很好的描述(确实,它是从 2006 年开始的,但它处理的是当时相当新的 JDK 1.6,所以从版本上来说它一点也不旧):

    http://www.javarants.com/2006/04/30/simple-and-efficient-xml-parsing-using-jaxb-2-0/

    【讨论】:

    • 很高兴知道您的问题已解决。只是想知道这(在这篇文章中解决)与我发布的内容有何不同?
    • 好吧,老实说,部分原因是对大型框架的恐惧,部分原因是懒惰:)(两者都很糟糕且令人遗憾)。首先,从文档来看,EMF 似乎是一个相当复杂的框架,它不仅用于 XML 处理,还用于大量其他事情,而且我总是尽可能避免使用如此繁重的框架(这只是个人喜好,我不是说一般来说是不好的)。其次,我很懒,EMF 使用了我不知道的非标准 XML 解析 API,因此我更喜欢使用标准 Java XML API 的解决方案。
    • 确实,不管你是否喜欢 EMF,我都建议不要使用它(“因为 EMF 对于这样一个小问题来说太大了。”)除非你有没有选择。并且在解析器上,再次引用“所以只需使用你想要的任何东西进行解析,为循环中的每个创建一些StringStream或其他东西,然后传递给JAX-B或EMF。"
    【解决方案3】:

    文档投影可能是这里的答案。 Saxon 和许多其他 XQuery 处理器提供了这个选项。如果您有一个从大型文档中选择少量数据的相当简单的查询,则查询处理器会分析查询以确定树的哪些部分需要可用于查询,哪些部分可以在处理过程中丢弃。生成的树通常只有完整文档大小的 1%。撒克逊人的详细信息:

    http://saxonica.com/documentation/sourcedocs/projection.xml

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-28
      • 1970-01-01
      • 2015-08-29
      • 2012-07-14
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 2015-08-26
      相关资源
      最近更新 更多