開始在 Python 中使用 XML 的一個主要要素是排列出所有可用模塊的可比性能力。在他的新 Python 專欄“可愛的 Python”的第一部分中,David Mertz 簡要描述了最流行和實用的關于 XML 的 Python 模塊,并指出可以下載的單獨模塊以及可供閱讀的參考資料。本文有助于確定哪些模塊最適合特定任務。
在許多情況下,Python 是使用 XML 文檔的理想語言。像 Perl、REBOL、REXX 和 TCL 一樣,它是一種靈活的腳本語言,并且有強大的文本操作能力。而且,XML 文檔除了編碼大多數類型的文本文件(或流文件),通常還編碼大量復雜的數據結構。文本處理中常見的“讀取幾行,并將它們與一些規則表達式比較”樣式通常不能很好地適合對 XML 進行徹底語法分析和處理。幸好,Python(與大多數其它語言相比)不僅有直接處理復雜數據結構的方法(通常使用類和屬性),還有許多 XML 相關的模塊可以幫助語法分析、處理和生成 XML。
關于 XML,要記住一個總體概念:可以驗證或非驗證方式處理 XML 文檔。在以前的處理類型中,讀取 XML 文檔之前,必須先讀取“文檔類型定義”(DTD)。這種情況下,處理將總體計算 XML 文檔的簡單句型規則,還將計算 DTD 的特定語法約束。大多數情況下,使用非驗證處理就可以了(通常運行更快,更適合程序) -- 我們相信文檔創建者遵循文檔范圍的規則。在下面討論的大多數模塊都是非驗證型;如果存在驗證選項,則描述將指出。
中心資源庫 (Vaults of Parnassus)(請參閱參考資料)最近已成為查找 Python 資源的標準方法??梢栽谀莻€站點上找到所有以下討論的模塊(通過鏈接到各自模塊所有者的站點)。特別地,可以在資源庫中找到 PyXML 發行版,它是 tar 文件和 Win32 形式的安裝程序。
Python 的 XML 特殊興趣組 (XML-SIG)
XML-SIG 的成員執行了許多 -- 或大部分 -- 維護 Python 一部分 XML 工具的任務。與其它 Python SIG 一樣,XML-SIG 要維護郵件發送列表、列表檔案、有用的參考大權、文檔、標準包和其它資源。閱讀了本文中的概述后,最好從 XML-SIG Web 頁面入手。
根據本文中講述的特定重點,XML-SIG 維護了 PyXML 發行版。這個包包含了許多本文中討論的模塊,一些“入門”文檔,一些演示代碼和其它一些 XML-SIG 決定放入該發行版的東西。給定的包也許不會總是包含每個獨立模塊或工具的最新版本,但下載 PyXML 發行版是個好主意。以后,可以隨時添加任何未包含的模塊,或者已包含模塊的新版本(以及許多 PyXML 發行版提供的服務所未包含的模塊)。
模塊:XMLLIB 模塊(標準)
“不包括在標準發行版中”,Python 1.5.* 帶有模塊 [xmllib]。Python 1.6 也許結合了更多 XML-SIG 的成就,但它仍是測試版。[xmllib] 是一個非驗證的低級語法分析器。[xmllib] 的工作方式是用應用程序覆蓋 XMLParser 類,并提供處理文檔元素(如特定或類屬標記,或字符實體)的方法。
作為正在使用的 [xmllib] 示例,PyXML 發行版包括一個叫做 'quotations.dtd' 的 DTD,以及這個 DTD 的文檔 'sample.xml'(請參閱參考資料,以獲取本文中提到的文件的檔案文件)。以下的代碼顯示了 'sample.xml' 中每段引言的前幾行,并生成了非常簡單的未知標記和實體的 ASCII 指示符。經過分析的文本作為連續流來處理,所使用的任何累加器都由程序員負責(如標記中的字符串 (#PCDATA),或所遇到的標記的列表/詞典)。
嘗試 xmllib 的代碼
#-------------------- try_xmllib.py --------------------#
import xmllib, string
class QuotationParser(xmllib.XMLParser):
"""Crude xmllib extractor for quotations.dtd document"""
def __init__(self):
xmllib.XMLParser.__init__(self)
self.thisquote = '' # quotation aclearcase/" target="_blank" >ccumulator
def handle_data(self, data):
self.thisquote = self.thisquote + data
def syntax_error(self, message): pass
def start_quotations(self, attrs): # top level tag
print '--- Begin Document ---'
def start_quotation(self, attrs):
print 'QUOTATION:'
def end_quotation(self):
print string.join(string.split(self.thisquote[:230]))+'...',
print '('+str(len(self.thisquote))+' bytes)'
self.thisquote = ''
def unknown_starttag(self, tag, attrs):
self.thisquote = self.thisquote + '{'
def unknown_endtag(self, tag):
self.thisquote = self.thisquote + '}'
def unknown_charref(self, ref):
self.thisquote = self.thisquote + '?'
def unknown_entityref(self, ref):
self.thisquote = self.thisquote + '#'
if __name__ == '__main__':
parser = QuotationParser()
for c in open("sample.xml").read():
parser.feed(c)
parser.close()
其它語法分析模塊
PyXML 發行版包含了幾個具有各種功能的附加語法分析模塊。提供這些模塊是為了對基本 [xmllib] 模塊做一些改進。
[pyexpat] 是 GPL 方式的 XML 語法分析器工具箱 'expat' 的封裝程序。'expat' 是用 C 語言寫的庫,這就意味著任何想要利用它的語言都可以使用它。'expat' 是非驗證型,因此它比原來的 Python 語法分析器快很多。[sgmlop] 的目的與 [pyexpat] 相同。它也是非驗證型,而且也用 C 語言編寫。[pyexpat] 可以作為 MacOS 二進制使用,[sgmlop] 可以當作 Win32 二進制使用;但如果您需要使用不同的平臺,那么就要用 C 編譯器為您自己的平臺構建模塊。
[xmlproc] 是 python 原有的語法分析器,它執行幾乎完整的驗證。如果需要驗證型語法分析器, [xmlproc] 是 Python 當前唯一的選擇。同樣,[xmlproc] 提供其它語法分析器所不具備的各種高級和測試接口。
如果決定使用 XML 的簡單 API (SAX) -- 它應該用于復雜的事物,因為其它大部分工具都構建在它之上 -- 將為您完成許多語法分析器的分類工作。在 PyXML 發行版中,[xml.sax.drivers] 包含許多語法分析器的瘦封裝程序,包括所有那些已討論過的、名稱形式為 'drv_*.py' 的語法分析器。但是,一般使用高級 SAX 設施訪問驅動器,該設施自動選擇系統上“最佳”的可用語法分析器:
選擇語法分析器
#------------- selecting the best parser ---------------#
from xml.sax.saxext import *
parser = XMLParserFactory.make_parser()
包:SAX
以上,我們已提到 SAX 會自動選擇要使用的語法分析器;但 SAX 是什么?一個較好的答案是:
“SAX(XML 的簡單 API)是 XML 語法分析器的公用語法分析器接口。它允許應用程序作者編寫使用 XML 語法分析器的應用程序,但是它卻獨立于所使用的語法分析器。(將它看作 XML 的 JDBC。)”
-- Lars Marius Garshol, SAX for Python(請參閱參考資料)
SAX -- 如同它提供的語法分析器模塊的 API -- 基本上是一個 XML 文檔的順序處理器。使用它的方法與 [xmllib] 示例極其相似,但更加抽象。定義語法分析器類,應用程序員將定義一個 'handler' 類,該類將注冊所使用的語法分析器。必須定義四個 SAX 接口(每個接口都有幾個方法):DocumentHandler、DTDHandler、EntityResolver 和 ErrorHandler。已提供了所有這些接口的基類,但大多數情況下,最簡單的方法是繼承 'HandlerBase',因為這個類繼承了所有四個接口??梢圆挥每紤]想要做什么。某些代碼將幫助解釋這一點;該樣本執行與 [xmllib] 示例相同的任務。
嘗試 SAX 的樣本代碼
#--------------------- try_sax.py ----------------------#
import string
from xml.sax import saxlib, saxexts
class QuotationHandler(saxlib.HandlerBase):
"""Crude sax extractor for quotations.dtd document"""
def __init__(self):
self.in_quote = 0
self.thisquote = ''
def startDocument(self):
print '--- Begin Document ---'
def startElement(self, name, attrs):
if name == 'quotation':
print 'QUOTATION:'
self.in_quote = 1
else:
self.thisquote = self.thisquote + '{'
def endElement(self, name):
if name == 'quotation':
print string.join(string.split(self.thisquote[:230]))+'...',
print '('+str(len(self.thisquote))+' bytes)'
self.thisquote = ''
self.in_quote = 0
else:
self.thisquote = self.thisquote + '}'
def characters(self, ch, start, length):
if self.in_quote:
self.thisquote = self.thisquote + ch[start:start+length]
if __name__ == '__main__':
parser = saxexts.XMLParserFactory.make_parser()
handler = QuotationHandler()
parser.setDocumentHandler(handler)
parser.parseFile(open("sample.xml"))
parser.close()
與 [xmllib] 相比,關于示例要注意兩件小事:'parseFile()'/'parse()' 方法處理整個流/字符串,所以不必為語法分析器創建循環;向 'characters()' 提供了大量數據,自變量會指出數據的大小和位置以及傳遞的字符串。不要假設變量 'ch' 將以什么形式傳送給 'characters()'。
包:DOM
DOM 是一種 XML 文檔的高級樹型表示。該模型并非特定于 Python,而是一種普通 XML 模型(請參閱參考資料以獲取進一步信息)。Python 的 DOM 包是針對 SAX 構建的,并且包括在 PyXML 發行版中。由于篇幅關系,沒有將代碼樣本加到本文中,但在 XML-SIG 的 "Python/XML HOWTO" 中給出了一個極好的總體描述。
“文檔對象模型”(DOM) 為 XML 文檔指定了樹型表示。頂級文檔實例是樹的根,它只有一個子代,即頂級元素實例;這個元素有表示內容和子元素的子節點,他們也可以有子代。定義的函數允許隨意遍歷結果樹,訪問元素和屬性值,插入和刪除節點,以及將樹轉換回 XML。
DOM 可以用于修改 XML 文檔,因為可以創建一棵 DOM 樹,通過添加新節點和來回移動子樹來修改這棵樹,然后生成一個新的 XML 文檔作為輸出。您也可以自己構造一棵 DOM 樹,然后將它轉換成 XML;用這種方法生成 XML 輸出比僅將 <tag1>...</tag1> 寫入文件的方法更靈活。
包:Pyxie
[pyxie] 模塊從 XML-SIG 構建到 PyXML 發行版之上,它為 XML 文檔提供了附加的高級接口。[pyxie] 將完成兩項基本操作:它將 XML 文檔轉換成一種更易于進行語法分析的基于行的格式;并且它提供了將 XML 文檔當作可操作樹處理的方法。[pyxie] 所使用的基于行的 PYX 格式是獨立于語言的,其工具適用于幾種語言??傊?,文檔的 PYX 表示與其 XML 表示相比,更易于使用常見的基于行的文本處理工具進行處理,如 grep、sed、awk、bash、perl,或標準 python 模塊,如 [string] 和 [re]。根據結果,從 XML 轉換到 PYX 可能節省許多工作。
[pyxie] 將 XML 文檔當作樹處理的概念與 DOM 中的思路相似。由于 DOM 標準得到許多編程語言的廣泛支持,那么如果 XML 文檔的樹型表示是必需的,大多數程序員會使用 DOM 標準而非 [pyxie]。
模塊:XML 語法分析器
“XML 語法分析器”這個叫法太籠統,也許還不太確切,實際上它是一種比較舊的工具,用于檢查 XML 文檔是否符合句法以及其結構是否完好(但對于 DTD 無效)。一個附加的實用程序類在進行檢查時會產生一些小麻煩,它會讓 HTML 文檔通過檢查(即使那些文檔沒有 XML 必需的結束標記)。這個模塊的適用范圍并不能覆蓋 PyXML 發行版中的所有模塊。但如果只想驗證一些 XML 文檔,那么設置和運行 XML 語法分析器還是很容易的。如果從命令行運行,則該模塊將在 STDIN 上檢查 XML 文檔,甚至不用將它導入程序。這是最簡單的做法。
XML_OBJECTS 0.1
如同其它高級工具,xml_objects 構建在 SAX 之上。構建 xml_objects 的目的是將 XML 文檔轉換成一個兩維網格表示,從而更易于在關系數據庫中存儲。
下一步
在下一個“可愛的 Python”專欄中,我們將進一步研究 xml.dom 模塊,它可能是 Python 程序員用來處理 XML 文檔的功能最強大的工具。
參考資料
Python 中處理 XML 的特殊興趣組 (SIG)
其它 Python SIG
SAX for Python 主頁
Pyxie 主頁,Python 的一個開放源碼 XML 處理庫
本文中提到的文件
"Processing XML with Perl",XML.com 上一篇很好的文章,它給出了適用于 Perl 的 XML 模塊的概述
關于作者
肯定有某種原因促使 David Mertz 寫下 Python 專欄??赡苁且驗?Monty 樂隊,他在十幾歲時很喜歡他們的唱片,現在他獲得了哲學碩士學位?,F在,他以寫計算機程序為生,并且還撰寫一些關于編寫計算機程序的文章,在從事編寫 Python 專欄時更是如此。David 歡迎您對這個專欄提出意見和建議??梢酝ㄟ^ mertz@gnosis.cx 與 David 取得聯系,在 http://gnosis.cx/publish/ 中刊登了他寫的文章。