[英]How to transform huge xml files in java?
正如標題所說,我有一個巨大的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來完成任務的簡潔方法?
StAX似乎是一個明顯的解決方案:它是一個拉解析器,而不是SAX的“推”或DOM的“緩沖全部”方法。 不能說我已經用過它了。 “StAX教程”搜索可能會派上用場:)
是的,只需編寫一個SAX內容處理程序,當遇到某個元素時,就可以在該元素上構建一個dom樹。 我用非常大的文件完成了這個,它運行得很好。
實際上非常簡單:只要遇到所需元素的開頭,就在內容處理程序中設置一個標志,然后從那里將所有內容轉發給DOM構建器。 遇到元素結尾時,將標志設置為false,並寫出結果。
(對於具有相同元素名稱的嵌套元素的更復雜情況,您需要創建堆棧或計數器,但這仍然很容易。)
我使用STX ( XML的流式轉換)獲得了很好的體驗。 基本上,它是XSLT的流式版本,非常適合以最小的內存占用來解析大量數據。 它在Java中有一個名為Joost的實現。
應該很容易想出一個STX轉換,忽略所有元素,直到元素匹配給定的XPath,復制該元素及其所有子元素(使用模板組中的標識模板),並繼續忽略元素直到下一個匹配。
UPDATE
我把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>
stx:transform
的pass-through="none"
配置默認模板(對於節點,屬性等)不產生輸出,但處理子元素。 然后stx:template
匹配XPath element/child
(這是放置匹配表達式的位置),它在“copy”組中“處理self”,這意味着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>
這是相應的輸出文件:
<?xml version="1.0" encoding="UTF-8"?>
<child attribute="value1">
text1<b>bold</b>
</child><child attribute="value2">
text2
<x:childX xmlns:x="http://x.example.com/x">
<!-- comment -->
yet more<b i="i" x:i="x-i" />
</x:childX>
</child>
異常格式化是跳過包含child
元素外部換行符的文本節點的結果。
既然你在談論GB,我寧願在考慮中優先考慮內存使用情況。 SAX需要大約2倍的內存,因為文檔大,而DOM需要它至少 5倍。 因此,如果您的XML文件大1GB,那么DOM將需要至少5GB的可用內存。 這不再有趣了。 因此,SAX(或其上的任何變體,如StAX)是最佳選擇。
如果您想要最節省內存的方法,請查看VTD-XML 。 它只需要比文件大一點的內存。
看看StAX ,這可能就是你所需要的。 IBM Developer Works上有很好的介紹。
對於如此大的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
您可以使用XMLEventReader
和javax.xml.stream包中的幾個XMLEventWriter
輕松完成此操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.