正如标题所说,我有一个巨大的xml文件(GBs)
<root>
<keep>
<stuff> ... </stuff>
<morestuff> ... </morestuff>
</keep>
<discard>
<stuff> ... </stuff>
<morestuff> ... </morestuff>
</discard>
</root>
我希望把它变成一个小得多的,只保留一些元素
我的解析器应该执行以下操作:
1.解析文件,直到相关元素开始
2.将整个相关元素(带子项)复制到输出文件。转到1.
答案 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
轻松完成此操作。