使用 XML: 瞭解解析 XML 的各種方法

瞭解基礎

從 XML 的出現至今大約有 9 年的時間了。對於可擴展標記語言來說這是一段不短的歷程。現在很難找到完全不用 XML 的應用程序了。

但是和客戶在一起的時候,仍然不可避免地發現基礎性的東西尚未被透徹地全部理解。對複雜的 XML 主題理解透徹的開發人員,最近卻發現對基礎性的東西(比如解析)的把握還存在很多不足,這真有點出人意料。

而對 XML 的處理是從何處開始的呢?沒錯,是解析。解析可能是開發人員能夠使用的最基本的服務。解析器讀取 XML 文檔,解釋語法並嚮應用程序傳遞有意義的對象。解析器可能還提供其他服務,比如驗證(保證文檔符合 XML Schema 或 DTD)或者名稱空間解析。

本文介紹了各種解析方法,着重分析了各自的優缺點,幫助您在下一個項目中選擇適當的工具。文中包含大量文章的鏈接,選擇工具的時候可以詳細研究給定的 API。

解析的重要性

解析爲什麼重要?因爲所有 XML 處理都從解析開始。無論使用高層編程語言(如 XSLT)還是低層 Java 編程,第一步都是要讀入 XML 文件,解碼結構和檢索信息等等,這就是解析。

解析文檔時面臨的第一個選擇是採用現成的解析庫(基本上每種編程語言都有,包括 COBOL [Common Business Oriented Language])還是自己創建一個。答案非常簡單:選擇現成的庫。

坦白地說,XML 不是一種多麼複雜的語法,因此認爲可以自己通過正則表達式或其他特殊方法來解析的想法是可以理解的。但實際上卻很難成功:XML 語法要求支持多種編碼和很多難以捉摸的特性,比如 CDATA 節和實體。自定義的實現幾乎很難照顧到所有這些方面,因而造成了不兼容性。

相反,隨開發環境提供的解析器大都經過了與兼容性有關的測試。採用 XML 這樣的標準語法的主要原因是兼容其他應用程序和工具箱,這是真正值得使用經過良好測試的庫的情況之一。

多數解析器提供了至少兩種 API,通常是一個對象模型 API 和一個事件 API(也稱爲 API)。比如,Java 平臺同時提供了 DOM(文檔對象模型)和 SAX(Simple API for XML)。

這兩套 API 提供了相同的服務:文檔解碼、可選的驗證、名稱空間解析等等。差別不在於服務而在於 API 使用的數據模型。

關鍵的選擇:第一種方法

對象模型 API 定義了層次化對象模型來表示 XML 文檔。換句話說,對應 XML 語法中的每個概念定義相應的類:元素、屬性、實體、文檔。解析器讀入 XML 文檔的時候,建立 XML 語法和類之間的一對一映射。比如,每遇到一個標記,就實例化一個元素類。

毫不奇怪,對哪種數據模型最好存在一些爭議。W3C 規範化了 DOM,它的主要優點是可移植性:它是作爲一種 CORBA 接口定義的,被映射到很多語言。因此如果瞭解了 JavaScript 中的 DOM,也就知道了 Java、C++、Perl、Python 和其他語言中的 DOM。

另一種數據模型是 JDOM,一種針對 Java 優化的 DOM(專用於 Java),和 Java 語言結合得更緊密,但是按照定義缺乏可移植性。

儘管人們可以繼續商討對 XML 語法來說哪種數據模型最好,但我認爲沒有多少意義,因爲各種基於對象的 API 其優點和不足基本上是一樣的。從好的方面來說,如果熟悉 XML 語法的話,對象模型 API 更容易理解。因爲它直接從 XML 語法映射到類,很容易學習、使用和調試。

簡單的代價是效率,至少對很多項目而言是這樣。讀入文檔的時候,解析器根據語法結構創建對象。對很多應用程序來說,XML 語法並不是很合適:

  • XML 語法非常羅嗦,即使文檔很小,解析器也要創建很多對象。
  • 對 XML 詞彙表進行的優化通常針對的是存儲和數據傳輸效率,而不是處理,因而應用程序可能需要對數據進行預處理,比方說,在開始真正的處理之前,先計算部分和或者合併其他來源的數據。很多情況下,在處理之前必須將數據從 XML 對象模型複製到應用程序專用的對象模型或者數據庫。
  • 因爲這種對象模型是通用的,包含很多應用程序並不需要的對象之間的引用(比如,從子元素到父元素的反向引用)。這些引用進一步增加了內存消耗。

在桌面上處理小型文檔這可能不是大問題,但是在其他環境中,比如服務器上,對象模型固有的低效率是不可接受的。

第二種方法

第二種選擇是事件 API,比如 SAX。這個概念是上述對象模型方式的一種反映。只不過這種方法不根據 XML 語法定義通用的數據模型,其解析器依賴應用程序程序員建立定製的數據模型。

因此解析器可以做得更小,因爲只需要傳遞最少量的信息。更重要的是,和一個型號打天下的對象模型(不管對象模型多麼好)相比總的效率更高,程序員可以根據應用程序的需要定製對象模型。

它的優點很明顯:

  • 統計應用程序或總結信息的任何應用程序都可以從中獲益,因爲它們的數據模型只需計算總計而無需複製整個文檔。
  • 類似的,即使動態處理文檔的應用程序(比如把文檔加載到數據庫中)不需處理或者只需少量處理,也可從中受益,因爲根本不需要存儲數據。

由於減少了內存需求,事件 API 可以處理任意大小的文檔,包括大小超過可用內存的文檔。基於同樣的原因,這類 API 也非常適合多個進程併發執行和共享內存的服務器。

效率的代價是簡單性的損失。事件 API 一向以難用著稱,因爲應用程序員要負責更多的操作。雖然短期看來如此,但根據我的經驗,從中期和長期來看,效率上的改進足以抵消略微增加的複雜度。

流式 API 有兩種形式:推式和拉式。從歷史上看,推式方法更加流行,因爲這正是 SAX 採用的模型。推式方法正在實現標準化,很快將作爲 StAX 集成到 Java 平臺中。

兩者有什麼區別呢?區別在於由誰控制讀循環。和讀取文件的任何軟件一樣,解析器也是圍繞着讀循環(讀入文件的循環)創建的。

模式(SAX)下,解析器控制循環。實際上應用程序調用解析器的時候,在文件結束之前控制權不會返回給應用程序。前面已經提到,解析器回調應用程序以建立數據模型,解析器處於控制地位。

模式下,應用程序控制循環。循環中應用程序負責反覆調用解析器,直到文件結束。

推模式最適合邊讀入邊處理 XML 文檔,比如讀入 RSS 提要並顯示爲 HTML 網頁。對於使用 XML 存儲數據的多數應用程序來說,“讀文檔”用對解析器的一次調用實現最方便。

拉模式更適合於處理不同 XML 詞彙表的文檔。這類應用程序通常需要嗅探輸入(讀入前幾行)以根據詞彙表決定調用子例程。

對於控制解析器的應用程序而言,一次循環是必要的,因爲應用程序很容易在嗅探前面幾行之後停止讀入。

第三種方法

如果不提到另一種選擇,即 XML 編組庫形式的解析,如 Castor,本文就不完整。該方法介於對象模型和事件方法之間。

其思想是從 XML Schema 生成一個對象模型而不是通用模型(如 DOM),解析器生成更加針對所用詞彙表的數據模型。比方說,如果詞彙表處理的是發貨單,那麼可以預料其中會包含發送方、接收方、日期、產品類別、產品標識、單價和總價。DOM 將這些元素映射到一個一般性的元素類。編組庫 爲發送方、接收方、日期、產品類別、產品標識、單價、總價和文檔中出現的其他元素創建專門的類。

從處理的是根據詞彙表定製(與根據應用程序的需要定製可能相同,也可能不同)的而不是通用數據模型這方面來講,編組庫具備事件 API 的一些優點。

如何寫入 XML 呢?

解析器讀取和解碼 XML 文檔,將其從磁盤上轉到內存中。那麼另一個方向上的移動該如何處理呢?如果應用程序需要將數據存儲到 XML 文件中怎麼辦?

雖然我建議您避免使用特殊的例程解碼 XML 文檔,但是對於寫入 XML 沒有這樣的疑慮。讀的時候必須保證實現了所有的規則,包括一些隱晦之處。但是寫入的時候,則可以實現一個小型的、可工作的詞彙表子集。

但是多數對象模型 API 仍然承擔了雙重職責,除了讀以外還要能將對象樹寫入磁盤。如果使用事件 API,就可以從數據結構生成寫事件(請參閱參考資料)。

結束語

那麼結論是什麼呢?用於讀 XML 文檔的 API 對應用程序的總體性能有重要影響,因此一定要花時間熟悉各種選項,爲您的平臺、編程語言,更重要的是爲您的項目做出最佳選擇。

一般而言,事件 API 佔用的資源更少,因此效率更高,但是如果無論如何都要將整個文檔保存到內存中,那麼對象 API 更好一些,因爲可以節省大量代碼。

請參閱 參考資料 列表,其中包括很多有關使用 XML 解析器的文章。最重要的是,不要用特殊的代碼來解碼 XML 文檔。如果沒有完全實現標準,就會造成兼容性問題,這樣的風險太高了。


參考資料

學習

  • 您可以參閱本文在 developerWorks 全球網站上的 英文原文

  • 理解 DOM”(Nicholas Chase,developerWorks,2003 年 7 月):瞭解 DOM,一種標準的文檔對象模型 API。文中介紹了 DOM 文檔的結構以及如何使用 Java 技術從 XML 文件創建文檔、修改和檢索結果。

  • SAX,功能強大的 API”(Benoît Marchal,developerWorks,2001 年 8 月):瞭解何時使用 SAX 代替 DOM,文中還介紹了常用的 SAX 接口,包括很多詳細的 Java 應用程序的例子。

  • 技巧: 用於靈活處理的SAX 過濾器”((Uche Ogbuji,developerWorks,2003 年 7 月):使用 SAX 篩選器創建可維護性更好的代碼,從簡單、獨立的模塊開始創建複雜的 XML 處理行爲。

  • 用 JDOM 簡化 XML 編程”(Wes Biggs 和 Harry Evans,developerWorks,2001 年 5 月):討論了針對 Java 語言優化的另外一種對象模型 API。

  • Castor JDO 入門”(Bruce Snyder,developerWorks,2002 年 10 月):深入瞭解 SAX API。

  • 超越 DOM、SAX 和 XSLT 的限制”(David Mertz,developerWorks,2001 年 10 月):考察了每種模型的侷限性和可能的改進方法。

  • 技巧: 實現 XMLReader”(Benoît Marchal,developerWorks,2003 年 3 月):瞭解如何通過 SAX API 寫入 XML 文檔。

  • 技巧:從 DOM 轉換” 和 “技巧:從 SAX 轉換”(Brett McLaughlin,developerWorks,2001 年 4 月):在 DOM 和 SAX 之間來回轉換以便與應用程序進行通信。

  • IBM XML 認證:瞭解如何才能成爲一名 IBM 認證的 XML 及相關技術的開發人員。

  • XML 技術庫:developerWorks 中國網站 XML 專區提供了大量技術文章和技巧、教程、標準以及 IBM 紅皮書。

  • developerWorks 技術活動 網絡廣播:隨時關注技術的最新進展。

獲得產品和技術

  • 使用 IBM 試用軟件 構建您的下一個開發項目,這些軟件可直接從 developerWorks 下載。

討論


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章