2011-10-24 82 views
1

我正在使用SAX解析一些大型的XML文件,我想問以下問題:XML文件具有複雜的結構。如下所示:Java Sax解析複雜的大型XML文件

<library> 
    <books> 
    <book> 
     <title></title> 
    <img> 
     <name></name> 
     <url></url> 
    </img> 
    ... 
    ... 
    </book> 
    ... 
    ... 
</books> 
<categories> 
    <category id="abcd"> 
     <locations> 
     <location>...</location> 
    </locations> 
    <url>...</url> 
    </category> 
    ... 
    ... 
</categories> 
<name>...</name> 
<url>...</url> 
</library> 

事實是這些文件每個都超過50MB,並且在不同的上下文中重複了很多標籤。 url/books/book/img下,還可以在/ library下和/ library/categories/category下等。

我的SAX解析器使用DefaultHandler的子類,其中我重寫了startElement和endElement方法(等等)。但問題在於,由於這些XML文件的業務邏輯,這些方法在代碼行方面非常龐大。我用了很多

if ("url".equalsIgnoreCase(qName)) { 
    // peek at stack and if book is on top 
    // ... 
    // else if category is on top 
    // ... 
} else if (....) { 
} 

我想知道是否有更正確/正確/優雅的方式來執行XML解析。

謝謝大家

+0

也許XSLT會很有用。它的聲明語法似乎更適合於你所擁有的「模式匹配」。但由於在XSLT中進行處理的限制,您可能必須使用擴展功能和/或元素。否則,您可能需要考慮使用規則引擎(例如Drools或其他Rete算法實現)來根據輸入匹配執行業務邏輯。 –

+0

SAX解析是非常難以編碼的,特別是對於複雜結構的xml?你看過vtd-xML嗎?它保留了DOM的大部分好處,沒有內存/處理開銷...... –

回答

0

不知道是否你問1)是否有別的東西,你可以除了檢查標籤對一串字符串做或2)如果有一種替代長,如果,則 - 其他種類的聲明。

1的答案不是我找到的。其他人可能會解決這個問題。

2的答案取決於您的域名。我看到的一種方式是,如果要從XML文件中提取一堆對象,則可以使用工廠方法。

因此,第一個工廠方法具有long if then else語句,該語句只是將XML傳遞給相應的類。然後,每個類都有一個方法,如constructYourselfFromXmlString。這將改進您的設計,因爲只有對象本身知道XML中的私有數據才能保證它們。

這個很難的原因是,如果你考慮一下,將Object導出到XML並導入回來確實違反了封裝。沒有什麼可以做的,只是。這至少讓事情更加封裝。

HTH

+0

其實我的問題是你說的第一個問題。 – gpol

+0

如果您有大量類,則額外優化將使用反射將所有構造函數一起收集到哈希映射中,然後通過字符串鍵將其拖出。這將刪除醜陋的大聲明,但會用一些醜陋的反射代替它。 – Thom

0

與情緒,即導出對象到XML是違反封裝的達成一致,用於處理該被嵌套在不同長度的標籤的實際技術不是非常難以使用SAX。

基本上,請保留一個StringBuffer,它將在文檔中保留您的「位置」,這將成爲您當前所在的嵌套標記表示的目錄。例如,如果當前字符串緩衝區的內容是/library/book/img/url,那麼您知道它是一本書中圖像的URL,而不是某個類別的URL。

確保您的「路徑跟蹤」算法正確後,您就可以通過使用字符串匹配來更好地處理對象創建例程。取而代之的

if ("url".equalsIgnoreCase(qName)) { 
    ... 
} 

你現在可以替代

if (location.equalsIgnoreCase("/library/book/img/url")) { 
    ... 
} 

如果由於某種原因,這並不能吸引你,還是有其他的解決方案。例如,您可以創建一個SAX處理程序,該處理程序實現了一系列處理程序,其中頂級處理程序負責處理它是XML文檔的一部分,並且一旦完成,它就會自動從堆棧中彈出。使用這樣的方案,每個對象都由它自己獨特的單個處理程序創建,並且一些處理程序基本上檢查並指導哪些「對象創建」處理程序在適當的時間被推到處理堆棧上。

我已經使用了這兩種技術。兩者都有優勢,哪一個最好取決於輸入和所需的對象。

1

什麼你可以做的就是實現獨立ContentHandler針對不同上下文。例如寫一個<books>,一個用於<categories>和一個頂級的。

然後,只要booksstartElement方法被調用,您立即使用XMLReader.setContentHandler()切換ContentHandler。然後<books>特定的ContentHandler切換回頂層處理程序,直到其endElement方法被調用爲books

這樣每個ContentHandler都可以專注於他的XML的特定部分,而不需要知道所有其他部分。

唯一醜陋的部分是特定的處理程序需要知道頂級處理程序以及何時切換回它,這可以通過提供一個簡單的「處理程序堆棧」來處理。

0

您可以重構您的SAX內容處理,以便您註冊一組規則,其中每個規則都有一個適用於查看它是否與元素相匹配的測試,以及一個如果它執行就執行的操作。這更接近XSLT處理模型,同時仍在進行流處理。或者您可以轉移到XSLT - 處理50Mb輸入文件完全在現代XSLT處理器的能力範圍內。