2008-12-10 55 views
18

(以下所有的是用Java寫的)解析非常大的XML文檔(多一點)在Java中

我必須建立一個將作爲輸入的XML文檔,潛在的應用程序,很大。該文件是加密的 - 不是XMLsec,但我的客戶的預先存在的加密算法 - 將分三個階段進行處理:

首先,流將根據上述算法進行解密。

其次,擴展類(由第三方對我提供了一個API編寫)將讀取該文件的某些部分。讀取的數量不可預測 - 特別是不能保證位於文件頭部,但可能出現在XML中的任何位置。

最後,另一擴展類(同樣處理)將細分輸入XML爲1..1子文件。這些可能會在某些部分與第二個操作處理的文檔部分重疊,也就是說:我相信我需要倒退我用來處理這個對象的任何機制。

這裏是我的問題:

有沒有辦法做到這一點沒有在同一時間去閱讀整片數據到內存?很明顯,我可以將解密作爲輸入流過濾器來實現,但我不確定是否可以按照我描述的方式解析XML;通過遍歷文檔需要收集第二步的信息,然後通過倒回文檔並再次傳遞以將其分割成作業,理想地釋放文檔中不再使用的所有部分之後他們已經通過了。

回答

3

您可以使用具有非常大的緩衝區大小的BufferedInputStream,並在擴展類工作之前使用mark(),之後使用reset()

如果擴展類需要很遠到文件的部分,那麼這可能會變得非常內存密集型,「雖然。

更常用的解決方案是編寫自己的BufferedInputStream - 如果要緩衝的數據超過某個預設閾值,則緩衝到磁盤。

1

你可能會XOM感興趣:

XOM是,它是一個 雙碼流/基於樹的API相當獨特。 在構建文檔時仍然可以處理 樹中的單個節點。使XOM程序 的運行速度幾乎與底層解析器可提供數據的 一樣快。你 不需要等待文件 被完全解析,然後你可以 開始使用它。

XOM的內存效率非常高。如果 將整個文檔讀入內存,則 XOM儘可能少地使用內存。 更重要的是,XOM允許您在創建過濾文檔時使用 ,因此您無需構建您不感興趣的樹的部分 。對於 實例,可以跳過構建文本 只代表邊界 空白的節點,如果這樣的空白區域是 在您的應用程序中不重要。 您甚至可以逐件處理文件 ,並在完成後丟棄每件 。 XOM已被 用於處理大小爲012 GB的數據。

+1

這看起來像一個有趣的,潛在有用的方法,但無處 文檔有沒有暗示的方式來控制你所描述的方式 文檔的解析。我相信你可以這樣做,但是 的功能沒有以合理的方式記錄下來。 – 2008-12-10 14:05:22

7

這聽起來像是StAX的工作(JSR 173)。 StAX是一個拉解析器,這意味着它或多或少像SAX這樣基於事件的解析器,但是您可以更好地控制何時停止讀取,哪些元素需要拉動,...

這個可用性解決方案將取決於你的擴展類實際在做什麼,如果你有他們的實施控制等等......

重點是如果文檔非常大,你可能想要使用基於事件解析器而不是基於樹的,所以你不會使用大量的內存。

StAX的實現可以從SUN(SJSXP),Codehaus或幾個其他供應商處找到。

+0

這看起來很有前途,只要我能有效地接觸它。看起來我必須將StAX公開給我的API客戶端,這並不理想,但至少它看起來像那些功能。你可以修改你的文章推薦實施,而不是清單? – 2008-12-10 15:41:25

3

我會寫的InputStream定製實現,解密文件中的字節,然後使用SAX因爲它涉及的料流解析生成的XML。

SAXParserFactory.newInstance().newSAXParser().parse(
    new DecryptingInputStream(), 
    new MyHandler() 
); 
0

看看XOM庫。您正在尋找的示例是源代碼分發示例目錄中的StreamingExampleExtractor.java。這顯示了一種技術,用於執行大型xml文檔的流式分析,僅構建特定節點,處理它們並丟棄它們。這與sax方法非常相似,但內置了更多的解析能力,因此可以非常容易地實現流解析。

如果你想在更高層次上工作,請看NUX。這提供了一個高層次的流xpath API,它只能讀取評估xpath所需的數據量到內存中。