开始在 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 accumulator
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 乐队,他在十几岁时很喜欢他们的唱片,现在他获得了哲学硕士学位。现在,他以写计算机程序为生,并且还撰写一些关于编写计算机程序的文章,在从事编写 Python 专栏时更是如此。David 欢迎您对这个专栏提出意见和建议。可以通过 mertz@gnosis.cx 与 David 取得联系,在 http://gnosis.cx/publish/ 中刊登了他写的文章。
文章来源于领测软件测试网 https://www.ltesting.net/