您可能已經知道語法分析器有兩類接口 - 基于對象的(如:DOM)和基于事件(如:SAX)的接口。
DOM是基于對象的語法分析器的標準 API。
作為基于對象的接口,DOM 通過在內存中顯示地構建對象樹來與應用程序通信。對象樹是 xml 文件中元素樹的精確映射。
DOM 易于學習和使用,因為它與基本 XML 文檔緊密匹配。然而,對于大多數應用程序,處理 XML 文檔只是其眾多任務中的一種。例如,記帳軟件包可能導入 XML 發票,但這不是其主要活動。計算帳戶余額、跟蹤支出以及使付款與發票匹配才是主要活動。記帳軟件包可能已經具有一個數據結構(最有可能是數據庫)。DOM 模型不太適合記帳應用程序,因為在那種情況下,應用程序必須在內存中維護數據的兩份副本(一個是 DOM 樹,另一個是應用程序自己的結構)。至少,在內存維護兩次數據會使效率下降。對于桌面應用程序來說,這可能不是主要問題,但是它可能導致服務器癱瘓。
對于不以 XML 為中心的應用程序,SAX 是明智的選擇。實際上,SAX 并不在內存中顯式地構建文檔樹。它使應用程序能用最有效率的方法存儲數據。
基于事件的語法分析器將事件發送給應用程序。這些事件類似于用戶界面事件,例如,瀏覽器中的 ONCLICK 事件或者 java 中的 AWT/Swing 事件。
事件通知應用程序發生了某件事并需要應用程序作出反應。在瀏覽器中,通常為響應用戶操作而生成事件:當用戶單擊按鈕時,按鈕產生一個 ONCLICK 事件。
在 XML 語法分析器中,事件與用戶操作無關,而與正在讀取的 XML 文檔中的元素有關。有對于以下方面的事件:
圖 3 顯示語法分析器在讀取文檔時如何生成事件。

清單 1 顯示了 XML 格式的清單。它詳細列出了不同公司對 XML 培訓的收費。圖 4 顯示了價目表文檔的結構。
<?xml version="1.0"?><xbe:price-list xmlns:xbe="http://www.psol.com/xbe2/listing8.1"> <xbe:product>XML Training</xbe:product> <xbe:price-quote price="999.00" vendor="Playfield Training"/> <xbe:price-quote price="699.00" vendor="XMLi"/> <xbe:price-quote price="799.00" vendor="WriteIT"/> <xbe:price-quote price="1999.00" vendor="Emailaholic"/></xbe:price-list>

XML 語法分析器讀取并解釋該文檔。每當它識別出文檔中的某些內容,就會生成一個事件。
讀取 清單 1 時,語法分析器首先讀取 XML 聲明并生成文檔開始事件。當它遇到第一個開始標記 <xbe:price-list> 時,語法分析器生成它的第二個事件來通知應用程序已經遇到了 price-list 元素。
接下來,語法分析器看到 product 元素的開始標記(為簡單起見,在本文其余部分,我將忽略名稱空格和縮進空格)并生成它的第三個事件。
在開始標記后,語法分析器看到 product 元素的內容: XML Training ,它產生另一個事件。
下一個事件指出 product 元素的結束標記。語法分析器已經完成了對 product 元素的語法分析。到目前為止,它已經激發了 5 個事件: product 元素的 3 個事件,一個文檔開始事件和一個 price-list 開始標記事件。
語法分析器現在移動到第一個 price-quote 元素。它為每個 price-quote 元素生成兩個事件:一個開始標記事件和一個結束標記事件。
是的,即使將結束標記簡化為開始標記中的 / 字符,語法分析器仍然生成一個結束事件。
有 4 個 price-quote 元素,所以語法分析器在分析它們時生成 8 個事件。最后,語法分析器遇到 price-list 的結束標記并生成它的最后兩個事件:結束 price-list 和文檔結束。
如圖 5 所示,這些事件共同向應用程序描述了文檔樹。開始標記事件意味著“轉到樹的下一層”,而結束標記元素意味著“轉到樹的上一層”。

請注意,語法分析器傳遞了足夠信息以構建 XML 文檔的文檔樹,但是與 DOM 語法分析器不同,它并不顯式地構建該樹。
現在,我敢肯定你已經糊涂了。應該使用哪一種類型的 API,應該何時使用它 - SAX 還是 DOM?不幸的是,這個問題沒有明確的答案。這兩種 API 中沒有一種在本質上更好;他們適用于不同的需求。
經驗法則是在需要更多控制時使用 SAX;要增加方便性時,則使用 DOM。
例如,DOM 在腳本語言中很流行。
采用 SAX 的主要原因是效率。SAX 比 DOM 做的事要少,但提供了對語法分析器的更多控制。當然,如果語法分析器的工作減少,則意味著您(開發者)有更多的工作要做。
而且,正如我們已討論的,SAX 比 DOM 消耗的資源要少,這只是因為它不需要構建文檔樹。
在 XML 早期,DOM 得益于 W3C 批準的官方 API 這一身份。逐漸地,開發者選擇了功能性而放棄了方便性,并轉向了 SAX。
SAX 的主要限制是它無法向后瀏覽文檔。實際上,激發一個事件后,語法分析器就將其忘記。如您將看到的,應用程序必須顯式地緩沖其感興趣的事件。
使用Python解析XML的時候,需要 import xml.sax 和 xml.sax.handler
xml.sax提供了3個函數以及 SAX 異常類
創建并返回一個SAX XMLReader對象
xml.sax.make_parser([parser_list])
創建一個 SAX 解析器并解析xml文檔
xml.sax.parse(filename_or_stream, handler[, error_handler])
創建一個XML解析器并解析xml字符串
xml.sax.parseString(string, handler[, error_handler])
要解析的XML
1 <?xml version="1.0"?> 2 <collection shelf="New Arrivals"> 3 <movie title="Enemy Behind"> 4 <type>War, Thriller</type> 5 <format>DVD</format> 6 <year>2003</year> 7 <rating>PG</rating> 8 <stars>10</stars> 9 <description>Talk about a US-Japan war</description>10 </movie>11 <movie title="Transformers">12 <type>Anime, Science Fiction</type>13 <format>DVD</format>14 <year>1989</year>15 <rating>R</rating>16 <stars>8</stars>17 <description>A schientific fiction</description>18 </movie>19 <movie title="Trigun">20 <type>Anime, Action</type>21 <format>DVD</format>22 <episodes>4</episodes>23 <rating>PG</rating>24 <stars>10</stars>25 <description>Vash the Stampede!</description>26 </movie>27 <movie title="Ishtar">28 <type>Comedy</type>29 <format>VHS</format>30 <rating>PG</rating>31 <stars>2</stars>32 <description>Viewable boredom</description>33 </movie>34 </collection>
1 #!/usr/bin/python 2 3 import xml.sax 4 5 class MovieHandler( xml.sax.ContentHandler ): 6 def __init__(self): 7 self.CurrentData = "" 8 self.type = "" 9 self.format = ""10 self.year = ""11 self.rating = ""12 self.stars = ""13 self.description = ""14 15 # 元素開始事件處理16 def startElement(self, tag, attributes):17 self.CurrentData = tag18 if tag == "movie":19 print "*****Movie*****"20 title = attributes["title"]21 print "Title:", title22 23 # 元素結束事件處理24 def endElement(self, tag):25 if self.CurrentData == "type":26 print "Type:", self.type27 elif self.CurrentData == "format":28 print "Format:", self.format29 elif self.CurrentData == "year":30 print "Year:", self.year31 elif self.CurrentData == "rating":32 print "Rating:", self.rating33 elif self.CurrentData == "stars":34 print "Stars:", self.stars35 elif self.CurrentData == "description":36 print "Description:", self.description37 self.CurrentData = ""38 39 # 內容事件處理40 def characters(self, content):41 if self.CurrentData == "type":42 self.type = content43 elif self.CurrentData == "format":44 self.format = content45 elif self.CurrentData == "year":46 self.year = content47 elif self.CurrentData == "rating":48 self.rating = content49 elif self.CurrentData == "stars":50 self.stars = content51 elif self.CurrentData == "description":52 self.description = content53 54 if ( __name__ == "__main__"):55 56 # 創建一個 XMLReader57 parser = xml.sax.make_parser()58 # turn off namepsaces59 parser.setFeature(xml.sax.handler.feature_namespaces, 0)60 61 # 重寫 ContextHandler62 Handler = MovieHandler()63 parser.setContentHandler( Handler )64 65 parser.parse("movies.xml")
執行結果:
*****Movie*****Title: Enemy BehindType: War, ThrillerFormat: DVDYear: 2003Rating: PGStars: 10Description: Talk about a US-Japan war*****Movie*****Title: TransformersType: Anime, Science FictionFormat: DVDYear: 1989Rating: RStars: 8Description: A schientific fiction*****Movie*****Title: TrigunType: Anime, ActionFormat: DVDRating: PGStars: 10Description: Vash the Stampede!*****Movie*****Title: IshtarType: ComedyFormat: VHSRating: PGStars: 2Description: Viewable boredom
《Python Cookbook》第12章:XML處理
新聞熱點
疑難解答