2010-07-20 32 views
2

我有一個巨大的XML文件高達1-2GB,顯然我無法一次解析整個文件,我不得不將它分解成幾部分,然後解析這些部分並對它們做任何事情。在Java中計算xml節點的最有效方法是什麼

如何計算某個節點的編號?所以我可以跟蹤需要分割多少部分文件。有沒有更好的方法來做到這一點?我向所有人開放的建議,謝謝

問題更新:

嗯,我沒有使用STAX,也許我使用它的邏輯是錯誤的,我解析的文件,然後對每個節點我正在獲取節點值並將其存儲在字符串構建器中。然後在另一種方法中,我通過stringbuilder並編輯輸出。然後我將該輸出寫入文件。我可以做不超過10000個這樣的對象。

這裏是例外,我得到:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
     at com.sun.org.apache.xerces.internal.util.NamespaceSupport.<init>(Unkno 
wn Source) 
     at com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.setNamespace 
Context(Unknown Source) 
     at com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.getXMLEvent(
Unknown Source) 
     at com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.allocate(Unk 
nown Source) 
     at com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(Unknown Sour 
ce) 
     at com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX.bridge(Unk 
nown Source) 
     at com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX.parse(Unkn 
own Source) 
     at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transfor 
mIdentity(Unknown Source) 
     at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transfor 
m(Unknown Source) 
     at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transfor 
m(Unknown Source) 

其實我覺得我的整個做法是錯誤的,就是我其實是想XML文件轉換成CSV樣本。下面是我如何做到這一點至今:

  • 讀/解析XML文件
  • 對於每一個元素節點獲取文本節點值
  • 打開流寫入到文件(臨時),爲n個節點,然後沖洗和關閉流
  • 然後打開從溫度讀取另一個流,使用commons條utils的和一些其他的東西,以創造適當的CSV輸出,然後將其寫入csv文件
+0

你是什麼意思「不超過10000個這樣的對象」? 你發現了什麼錯誤或異常? – 2010-07-20 11:16:39

+0

STAX API不使用大量內存,但如果您自己的程序在STAX執行迭代時存儲大量數據,那麼這不是STAX的錯誤。你需要整理你自己的內存管理,而不是選擇一個不同的XML API。 – skaffman 2010-07-20 11:39:39

+0

爲什麼你將這個值存儲在一個stringbuilder中,你爲什麼不能處理獨立的節點值? – josefx 2010-07-20 13:17:03

回答

4

SAX或STAX API將是您最好的選擇。他們並不是一次解析整個事物,而是一次只有一個節點,讓你的應用程序處理它。他們適合任意大的文件。

SAX是較舊的API,適用於推送模型,STAX較新,並且是拉解析器,因此使用起來相當容易,但對於您的要求,任何一個都可以。

請參閱this tutorial讓您開始使用STAX解析。

+0

+1提到StaX(拉)比SAX更易於使用。 – naikus 2010-07-20 11:14:42

0

你會更好使用基於事件的解析器等作爲SAX

1

我想你想避免創建一個DOM,所以SAXStAX應該是不錯的選擇。

SAX只是實現了一個simlpe內容處理程序,如果找到一個感興趣的元素,就會增加一個計數器。

2

對此,您可以使用流式解析器,如StAX。這不需要您一次讀取內存中的整個文件。

1

隨着SAX你不必拆分文件:它是流媒體,所以它只保存在內存中的當前位。編寫一個只需進行計數的ContentHandler非常簡單。而且速度非常快(根據我的經驗,幾乎和簡單閱讀文件一樣快)。

0

我認爲分割文件不是要走的路。您最好將xml文件作爲流處理,並使用SAX API(而不是DOM API)。

更好的是,您應該使用XQuery來處理您的請求。

Saxon是一個很好的Java/.Net實現(使用sax),即使在大文件上,它的速度也非常快。版本HE使用MPL開源許可證。

這裏是一個小例子:

java -cp saxon9he.jar net.sf.saxon.Query -qs:"count(doc('/path/to/your/doc/doc.xml')//YouTagToCount)" 
1

嗯,我沒有使用STAX,也許我使用它的邏輯是錯誤的,我解析的文件,然後對我的每個節點m獲取節點值並將其存儲在字符串構建器中。然後在另一種方法中,我通過stringbuilder並編輯輸出。然後我將該輸出寫入文件。我可以做不超過10000個這樣的對象。

通過這個描述,我會說是的,你使用它的邏輯是錯誤的。記憶中你太過分了。

不是分析整個文件,而是將所有節點值存儲到某個東西中,然後處理結果,您應該處理每個節點,並在解析時輸出。

有關您實際嘗試完成的內容以及輸入XML和無論什麼樣子的更多詳細信息,我們可能會幫助簡化。

0

通過擴展vtd-xml,可以高效地加載內存中的文檔,因爲它支持內存映射。與DOM相比,內存使用量不會爆炸一個數量級。你將能夠很容易地使用xpath來計算節點的數量。

相關問題