簡體   English   中英

如何在java中轉換巨大的xml文件?

[英]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,並寫出結果。

(對於具有相同元素名稱的嵌套元素的更復雜情況,您需要創建堆棧或計數器,但這仍然很容易。)

我使用STXXML的流式轉換)獲得了很好的體驗。 基本上,它是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:transformpass-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM