解析非常大的XML文件并编组到Java对象

Shi*_*gon 6 java xml

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

我的问题是,有没有办法按顺序解析(或只是部分解析)文件,然后只将那些部分编组到Java对象中,这样我就可以轻松处理它们而不会让内存陷入困境?

Kas*_*yap 5

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

无论如何,如果您的XML格式定义得很好,那么一种解决方法就是通过将整个文件分解为几个较小(但仍然定义明确)的XML片段来欺骗EMF.然后一个接一个地提供每个片段.我不知道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>
Run Code Online (Sandbox Code Playgroud)

然后它可以分解为一个XML,每个XML都以#开头<tag2>并以</tag2>.结尾.在java中,大多数解析器都会接受一个Stream,所以只需使用你想要的任何东西进行解析,<tag2>在循环中为每个解析器创建一些StringStream ,然后传递给JAX-B或EMF.

HTH


Shi*_*gon 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/