如何在java中转换巨大的xml文件?

时间:2010-05-05 13:46:10

标签: java xml parsing

正如标题所说,我有一个巨大的xml文件(GBs)

<root>  
<keep>  
   <stuff>  ...  </stuff>  
   <morestuff> ... </morestuff>  
</keep>  
<discard>  
   <stuff>  ...  </stuff>  
   <morestuff> ... </morestuff>
</discard>  
</root>  

我希望把它变成一个小得多的,只保留一些元素 我的解析器应该执行以下操作:
1.解析文件,直到相关元素开始 2.将整个相关元素(带子项)复制到输出文件。转到1.

使用SAX,第1步很容易,DOM解析器也不可能 第2步对SAX很烦,但使用DOM-Parser或XSLT很容易。

那么什么? - 是否有一种结合SAX和DOM-Parser来完成任务的简洁方法?

7 个答案:

答案 0 :(得分:10)

StAX似乎是一个明显的解决方案:它是一个拉解析器,而不是SAX的“推”或DOM的“缓冲全部”方法。不能说我已经用过它了。 "StAX tutorial" search可以派上用场:)

答案 1 :(得分:9)

是的,只需编写一个SAX内容处理程序,当遇到某个元素时,就可以在该元素上构建一个dom树。我用非常大的文件完成了这个,并且效果非常好。

实际上非常简单:只要遇到所需元素的开头,就在内容处理程序中设置一个标志,然后从那里将所有内容转发给DOM构建器。当遇到元素的结尾时,将标志设置为false,并写出结果。

(对于具有相同元素名称的嵌套元素的更复杂的情况,您需要创建堆栈或计数器,但这仍然很容易。)

答案 2 :(得分:5)

我使用STX XML的流转换)获得了很好的体验。基本上,它是XSLT的流式版本,非常适合以最小的内存占用来解析大量数据。它在Java中有一个名为Joost的实现。

应该很容易想出一个STX转换,忽略所有元素,直到元素匹配给定的XPath,复制该元素及其所有子元素(使用模板组中的标识模板),并继续忽略元素直到下一场比赛。

<强>更新

我将STX转换混合在一起,做了我理解你想要的东西。它主要依赖于STX专用功能,如模板组和可配置的默认模板。

<stx:transform xmlns:stx="http://stx.sourceforge.net/2002/ns"
    version="1.0" pass-through="none" output-method="xml">
    <stx:template match="element/child">
        <stx:process-self group="copy" />
    </stx:template>
    <stx:group name="copy" pass-through="all">
    </stx:group>
</stx:transform>

pass-through="none"的{​​{1}}配置默认模板(对于节点,属性等)不产生输出,但处理子元素。然后stx:transform匹配XPath stx:template(这是您放置匹配表达式的位置),它在“复制”组中“处理自我”,这意味着来自{{1的匹配模板在当前元素上调用。该组具有element/child,因此默认模板会复制其输入和处理子元素。当group name="copy"元素结束时,控制权将传递回调用pass-though="all"的模板,并再次忽略以下元素。直到模板再次匹配。

以下是输入文件的示例:

element/child

这是相应的输出文件:

process-self

异常格式化是跳过包含<root> <child attribute="no-parent, so no copy"> </child> <element id="id1"> <child attribute="value1"> text1<b>bold</b> </child> </element> <element id="id2"> <child attribute="value2"> text2 <x:childX xmlns:x="http://x.example.com/x"> <!-- comment --> yet more<b i="i" x:i="x-i" ></b> </x:childX> </child> </element> </root> 元素之外的换行符的文本节点的结果。

答案 3 :(得分:3)

由于你在谈论GB,我宁愿优先考虑内存使用情况。 SAX需要大约2倍的内存,因为文档大,而DOM需要至少 5次。因此,如果您的XML文件大1GB,那么DOM将需要至少5GB的可用内存。这不再有趣了。因此,SAX(或其上的任何变体,如StAX)是最佳选择。

如果您想要最节省内存的方法,请查看VTD-XML。它只需要比文件大一点更多的内存。

答案 4 :(得分:2)

看看StAX,这可能就是您所需要的。对IBM Developer Works有一个很好的介绍。

答案 5 :(得分:2)

对于如此大的XML文档,像Omnimark这样的流式架构是理想的。

它也不一定非常复杂。 Omnimark脚本如下所示,可以满足您的需求:

process

submit #main-input

macro upto (arg string) is
    ((lookahead not string) any)*
macro-end

find (("<keep") upto ("</keep>") "</keep>")=>keep
    output keep

find any

答案 6 :(得分:0)

您可以使用javax.xml.stream包中的XMLEventReader和几个XMLEventWriter轻松完成此操作。