DOM和SAX概念的總結

一 開發XML應用程序常用de幾種模型

您可以使用根據以下這些模型創建的API 來分析和操縱 XML 結構,這些模型可以是基於對象(基於樹)的,如文檔對象模型(Document Object Model,DOM);也可以是基於事件(基於流、推模型)的,如 Simple API for XML(SAX)。
JDOM試圖用 DOM 和 SAX 20% 的功能來滿足 80% 的用戶需求,它使用 SAX 和 DOM 解析器,作爲一組相
對較小的 Java 類被實現。而Java API for XML Parsing(JAXP)和MSXML提供了使用 DOM、SAX等處理XML文檔的通用接口。現在,.NET框架也提供了分別基於DOM的XmlDocment類以及基於流(拉模型)的XmlReader類等。

二 DOM、SAX及其比較與選擇

用於讀取和操作 XML 文件的標準是文檔對象模型DOM。 
DOM爲 XML 文檔的已解析版本定義了一組接口。解析器讀入整個文檔,然
後構建一個駐留內存的樹結構,然後您的代碼就可以使用 DOM 接口來操作這個樹結構。您可以遍歷樹以瞭解原始文檔包含了什麼,您可以刪除樹的幾個部分,還可以重新排列樹和添加新的分支,等等。
遺憾的是,因爲DOM 方法涉及讀取整個文件並將該文件存儲在一個樹結構中,而這樣可能是低效的、緩
慢的,並且很消耗資源:
DOM 構建整個文檔駐留內存的樹。如果文檔很大,就會要求有極大的內存。 
DOM 創建表示原始文檔中每個東西的對象,包括元素、文本、屬性和空格。如果您只需關注原始文檔的
一小部分,那麼創建那些永遠不被使用的對象是極其浪費的。
DOM 解析器必須在您的代碼取得控制權之前讀取整個文檔。對於非常大的文檔,這會引起顯著的延遲。 
這些僅僅是由文檔對象模型的設計引起的問題;撇開這些問題,DOM API 是解析 XML 文檔非常有用的
方法。

一種替代技術就是SAX。相比於文檔對象模型DOM,SAX 是讀取和操作 XML 數據的更快速、更輕量的方法。SAX 允許您在讀取文檔時處理它,從而不必等待整個文檔被存儲之後才採取操作。它不涉及 DOM 所必需的開銷和概念跳躍。

SAX API是一個基於事件的 API,適用於處理數據流,即隨着數據的流動而依次處理數據。
SAX API 在其解析您的文檔時發生一定事件的時候會通知您。在您對其響應時,您不作保存的數據將會
被拋棄。

在使用DOM的情況下,解析器做了絕大多數事情, 讀入XML文檔, 在這基礎之上創建對象模型,然後給你
一個對這個對象的引用(一個 Document對象),因而你可以操作使用它。SAX沒有期待解析器去做這麼多工作,所有SAX 要求的是解析器應該讀入XML文檔,同時根據所遇到的XML文檔的標籤向一個事件處理程序發出一系列事件,比如元素開始和元素結束,而事件處理器則處理該信息:你要自己寫一個XML文檔處理器類(XML document handler class)來處理這些事件,這意味着使所有標籤事件有意義還有用你自己的對象模型創建對象。所以你要完成:
    控制所有XML文檔信息的自定義對象模型。
    一個監聽SAX事件(事件由SAX解析器讀取你的XML文檔時產生)的文檔處理器,還有解釋這些事件創建你自定義對象模型中的對象。
如果你的對象模型簡單的話那麼SAX在運行時會非常快。在這種情況下,它會比DOM快,因爲它忽略了爲
你的信息創建一個樹形對象模型的過程。從另一方面來說,你必須寫一個SAX 文檔處理器來解釋所有的SAX事件(這會是一件很繁重的工作)。
基於事件的API 消除了在內存中構造樹的需要,卻不允許開發人員實際更改原始文檔中的數據。所以原始的文檔仍然保留完好無損;但是 SAX 提供了操作數據的手段,而後數據可以引入另一個進程或文檔。

[
要使用 XML 文檔做任何事情,你都必須讀取其中的信息。做這個工作的應用程序稱爲解析器。它設計用於分析文檔(這裏是指 XML 文件),以及做一些特定於該信息的事情。在諸如 SAX 這樣基於
事件的 API 中,解析器將向某種監聽器發送事件。在諸如 DOM 這樣基於樹的 API 中,解析器將在內存中構造一顆數據樹。
解析器的兩種類型分別是:非驗證 和 驗證。
非驗證解析器是適用於格式良好(well-formed)文檔的解析器。 它讀取每個信息單元,並將其添加到文檔 ―― 或者在 SAX 應用程序的情況下處理事件,而不管實際的結構和內容如何。 另一方面,驗證解析器根據已定義的語法檢查 XML 文檔的內容和結構。 有時,這個語法是文檔類型定義(Document Type Definition,DTD)的形式,但是它更可能在 XML Schema 文檔中定義。在任一種情況下,解析器都會檢查文檔,以確保每個元素和屬性都已定義,並且包含正確類型的內容。例如,您可以指定每個 order(訂單) 都有一個status(狀態)。 如果在沒有語法定義的情況下嘗試創建文檔,驗證解析器將會提示錯誤。 
已經由驗證解析器檢驗過的文檔被認爲是有效的文檔。
]

SAX 的幾個特徵解決了 DOM 的問題:

SAX 解析器向您的代碼發送事件。當解析器發現元素開始、元素結束、文本、文檔的開始或結束等時,它會告訴您。您可以決定什麼事件對您重要,而且可以決定要創建什麼類型的數據結構以保存來自這些事件的數據。如果您沒有顯式地保存來自某個事件的數據,它就被丟棄。 
SAX 解析器根本不創建任何對象,它只是將事件傳遞給您的應用程序。如果希望基於那些事件創建對象
,這將由您來完成。 
SAX 解析器在解析開始的時候就開始發送事件。當解析器發現文檔開始、元素開始和文本等時,代碼會
收到一個事件。您的應用程序可以立即開始生成結果;您不必一直等到整個文檔被解析完畢。更妙的是,如果您只查找文檔中某些內容,代碼一旦找到所要找的東西就可以拋出一個異常。該異常會停止 SAX 解析器,然後代碼用它找到的數據做它需要做的任何事。 

公平而言,SAX 解析器也有些問題引人關注:

DOM 所提供的豐富的標準功能在 SAX 中是沒有的。
SAX 事件是無狀態的。當 SAX 解析器在 XML 文檔中發現文本時,它就向您的代碼發送一個事件。該事
件僅僅給您發現的文本;它不告訴您什麼元素包含那個文本。如果您想知道這一點,則必須自己編寫狀態管理代碼。 
SAX 事件不是持久的。如果應用程序需要一個數據結構來對 XML 文檔建模,則必須自己編寫那樣的代
碼。如果您需要從 SAX 事件訪問數據,並且沒有把那個數據存儲在代碼中,那麼您不得不再次解析該文檔。 


考慮XML 代碼片斷

<?xml version="1.0"?>
<samples>
   <server>UNIX</server>
   <monitor>color</monitor>
</samples>

DOM 處理是如何工作的 

使用 DOM 時,數據以樹狀結構的形式被加載到內存中。例子的文檔在 DOM 中將表示爲節點,如下所示


矩形框表示元素節點,橢圓表示文本節點。
DOM 使用父子關係。例如,在這個例子中,samples 是具有五個孩子的根元素:三個文本節點(空白),以及兩個元素節點 server 和 monitor。
要認識到的一件重要事情是,server 和 monitor 節點實際上具有 null 值。相反,它們具有文本節點(UNIX 和 color)作爲孩子。

SAX 處理是如何工作的 

SAX 在讀取 XML 流的同時處理它們,這很像以前的自動收報機紙帶(ticker tape)。
而分析這個代碼片斷的 SAX 處理器一般情況下將產生以下事件: 

Start document
Start element (samples)
Characters (white space)
Start element (server)
Characters (UNIX)
End element (server)
Characters (white space)
Start element (monitor)
Characters (color)
End element (monitor)
Characters (white space)
End element (samples)

SAX API 允許開發人員捕捉這些事件並對它們作出反應。

SAX 處理涉及以下步驟:
    創建一個事件處理程序。 
    創建 SAX 解析器。 
    向解析器分配事件處理程序。 
    解析文檔,同時向事件處理程序發送每個事件。 

[什麼類型的SAX事件被SAX解析器拋出了哪? 這些事件實際上是非常簡單的。SAX會對每一個開始標籤拋出事件,對每一個結束標籤也是如此。它對#PCDATA和 CDATA 部分同樣拋出事件。你的文檔處理器 (對這些事件的監聽器)要解釋這些事件同時還要在他們基礎之上創建你自定義的對象模型。 你的文檔處理器必須對這些事件做出解釋,同時這些事件發生的順序是非常重要的。SAX同時也對processing instructions, DTDs, comments, 拋出事件. 但是它們在概念上是一樣的, 你的解析器要解釋這些事件(還有這些事件的發生順序)以及使他們有意義。]

基於樹的處理的優點和缺點 

DOM 以及廣義的基於樹的處理具有幾個優點。
首先,由於樹在內存中是持久的,因此可以修改它以便應用程序能對數據和結構作出更改。它還可以在任何時候在樹中上下導航,而不是像 SAX 那樣是一次性的處理。DOM 使用起來也要簡單得多。
另一方面,在內存中構造這樣的樹涉及大量的開銷。大型文件完全佔用系統內存容量的情況並不鮮見。此外,創建一棵 DOM 樹可能是一個緩慢的過程。

基於事件的處理的優點和缺點 

這種處理的優點非常類似於流媒體的優點。分析能夠立即開始,而不是等待所有的數據被處理。而且,由於應用程序只是在讀取數據時檢查數據,因此不需要將數據存儲在內存中。這對於大型文檔來說是個巨大的優點。事實上,應用程序甚至不必解析整個文檔;它可以在某個條件得到滿足時停止解析。一般來說,SAX 還比它的替代者 DOM 快許多。
另一方面,由於應用程序沒有以任何方式存儲數據,使用 SAX 來更改數據或在數據流中往後移是很困難的。


如何在 SAX 和 DOM 之間選擇 

選擇 DOM 還是選擇 SAX,這取決於下面幾個因素:

應用程序的目的:如果打算對數據作出更改並將它輸出爲 XML,那麼在大多數情況下,DOM 是適當的選擇。並不是說使用 SAX 就不能更改數據,但是該過程要複雜得多,因爲您必須對數據的一份拷貝而不是對數據本身作出更改。 
[由於 SAX 涉及在讀取數據時分析數據(而不是在存儲之後再分析),您可能認爲沒有辦法在分析數據之前更改數據。這就是SAX 2.0 版中新引入的 XMLFilter 要解決的問題。認識到能夠將 SAX 流“鏈接”在一起,從而能夠在數據到達最終目的地之前有效地操作它們。基本上,它像下面這樣工作:  創建 XMLFilter,這通常是一個簡單的類;       創建 XMLFilter 的一個實例,並將它的父親設置爲通常負責解析文件的 XMLReader;          將過濾器的內容處理程序設置爲通常的內容處理程序;           解析文件。         過濾器介於 XMLReader 和內容處理程序之間。]
一旦解析了 XML 文檔,還需要多次訪問那些數據嗎?如果您需要回過頭來訪問 XML 文件的已解析版本,DOM 可能是正確的選擇。而 SAX 事件被觸發時,如果您以後需要它,則由您(開發人員)自己決定以某種方式保存它。如果您需要訪問不曾保存的事件,則必須再次解析該文件。而 DOM 自動保存所有的數據。 
數據容量: 對於大型文件,SAX 是更好的選擇。 
數據將如何使用:如果只有數據中的少量部分會被使用,那麼使用 SAX 來將該部分數據提取到應用程序中可能更好。SAX 不會爲源文件中的每個東西創建對象;您要確定什麼是重要的。使用 SAX,您要檢查每個事件以瞭解它是否與您的需要有關,然後相應地處理它。更妙的是,一旦找到您正在尋找的東西,您的代碼就會拋出一個異常來完全停止 SAX 解析器。  另一方面,如果您知道自己以後會回頭引用已處理過的大量信息,那麼 SAX 也許不是恰當的選擇。 
對速度的需要: SAX 實現通常要比 DOM 實現更快。 

SAX 和 DOM 不是相互排斥的,記住這點很重要。您可以使用 DOM 來創建 SAX 事件流,也可以使用SAX 來創建 DOM 樹。事實上,用於創建 DOM 樹的大多數解析器實際上都使用 SAX 來完成這個任務!

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