进一步了解Python中的XML 工具


Posted in Python onApril 13, 2015

模块:xmllib

xmllib 是一个非验证的低级语法分析器。应用程序员使用的 xmllib 可以覆盖 XMLParser 类,并提供处理文档元素(如特定或类属标记,或字符实体)的方法。从 Python 1.5x 到 Python 2.0+ 以来, xmllib 的使用方法并没变化;在绝大多数情况下更好的选择是使用 SAX 技术,它也是种面向流的技术,对语言和开发者来说更为标准。

本文中的示例与原来专栏中的相同:包括一个叫做 quotations.dtd 的 DTD 以及这个 DTD 的文档 sample.xml (请参阅 参考资料,以获取本文中提到的文件的档案)。以下的代码显示了 sample.xml 中每段引言的前几行,并生成了非常简单的未知标记和实体的 ASCII 指示符。经过分析的文本作为连续流来处理,所使用的任何累加器都由程序员负责(如标记中的字符串 (#PCDATA),或所遇到的标记的列表或词典)。
清单 1: try_xmllib.py

import
         xmllib, string
    
    classQuotationParser

        (xmllib.XMLParser):
  """Crude xmllib extractor for quotations.dtd document"""
  
    
    def__init__

        (self):
    xmllib.XMLParser.__init__(self)
    self.thisquote = ''       
    
    # quotation accumulator
     
     
     defhandle_data

        (self, data):
    self.thisquote = self.thisquote + data
  
    
    defsyntax_error
        (self, message):
    
    
    pass
  defstart_quotations
        (self, attrs): 
    
    # top level tag
         
     
     print

         '--- Begin Document ---'
  
    
    defstart_quotation
        (self, attrs):
    
    
    print
         'QUOTATION:'
  
    
    defend_quotation
        (self):
    
    
    print

         string.join(string.split(self.thisquote[:230]))+'...',
    
    
    print

         '('+str(len(self.thisquote))+' bytes)\n'
    self.thisquote = ''
  
    
    defunknown_starttag

        (self, tag, attrs):
    self.thisquote = self.thisquote + '{'
  
    
    defunknown_endtag

        (self, tag):
    self.thisquote = self.thisquote + '}'
  
    
    defunknown_charref

        (self, ref):
    self.thisquote = self.thisquote + '?'
  
    
    defunknown_entityref

        (self, ref):
    self.thisquote = self.thisquote + '#'
    
    if

         __name__ == '__main__':
  parser = QuotationParser()
  
    
    for
         c 
    
    in
         open("sample.xml").read():
    parser.feed(c)
  parser.close()

验证

您可能需要展望标准 XML 支持的未来的原因是,在进行语法分析的同时需要进行验证。不幸的是,标准 Python 2.0 XML 包并不包括验证型语法分析器。

xmlproc 是 python 原有的语法分析器,它执行几乎完整的验证。如果需要验证型语法分析器, xmlproc 是 Python 当前唯一的选择。而且, xmlproc 提供其它语法分析器所不具备的各种高级和测试接口。

选择一种语法分析器

如果决定使用 XML 的简单 API (SAX) -- 它应该用于复杂的事物,因为其它大部分工具都是在它的基础上建立的 -- 将为您完成许多语法分析器的分类工作。 xml.sax 模块包含一个自动选择“最佳”语法分析器的设施。在标准 Python 2.0 安装中,唯一能选择的语法分析器是 expat ,它是种 C 语言编写的快速扩展。然而,也可以在 $PYTHONLIB/xml/parsers 下安装另一个语法分析器,以备选择。设置语法分析器很简单:
清单 2: Python 选择最佳语法分析器的语句

import
         xml.sax
parser = xml.sax.make_parser()

您还可以通过传递参数来选择特定的语法分析器;但考虑到可移植性 -- 也为了对今后更好的语法分析器的向上兼容性 -- 最佳方法是使用 make_parser() 来完成工作。

您可以直接导入 xml.parsers.expat 。如果这样做,您就能获得 SAX 界面并不提供的一些特殊技巧。这样, xml.parsers.expat 与 SAX 相比有些“低级”。但 SAX 技术非常标准,对面向流的处理也非常好;大多数情况下 SAX 的级别正合适。通常情况下,由于 make_parser() 函数已经能获得 expat 提供的性能,因此纯速度的差异很小。

什么是 SAX

考虑到背景因素,回答什么是 SAX 的较好答案是:

    SAX (XML 的简单 API)是 XML 语法分析器的公用语法分析器接口。它允许应用程序作者编写使用 XML 语法分析器的应用程序,但是它却独立于所使用的语法分析器。(将它看作 XML 的 JDBC。)(Lars Marius Garshol,SAX for Python)

SAX -- 如同它提供的语法分析器模块的 API -- 基本上是一个 XML 文档的顺序处理器。使用它的方法与 xmllib 示例极其相似,但更加抽象。应用程序员将定义一个 handler 类,而不是语法分析器类,该 handler 类能注册到任何所使用的语法分析器中。必须定义 4 个 SAX 接口(每个接口都有几个方法):DocumentHandler、DTDHandler、EntityResolver 和 ErrorHandler。创建语法分析器除非被覆盖,否则它还连接默认接口。这些代码执行与 xmllib 示例相同的任务:
清单 3: try_sax.py

"Simple SAX example, updated for Python 2.0+"
    
    import
         string
    
    import
         xml.sax
    
    from
         xml.sax.handler 
    
    import
         *
    
    classQuotationHandler

        
  (ContentHandler):
  """Crude extractor for quotations.dtd compliant XML document"""
  
    
    def__init__

        
  (self):
    self.in_quote = 0
    self.thisquote = ''
  
    
    defstartDocument
        
  (self):
    
    
    print

         '--- Begin Document ---'
  
    
    defstartElement

        
  (self, name, attrs):
    
    
    if

         name == 'quotation':
      
    
    print

         'QUOTATION:'
      self.in_quote = 1
    
    
    else:
    
    
      self.thisquote = self.thisquote + '{'
  
    
    defendElement

        
  (self, name):
    
    
    if

         name == 'quotation':
      
    
    print

         string.join(string.split(self.thisquote[:230]))+'...',
      
    
    print

         '('+str(len(self.thisquote))+' bytes)\n'
      self.thisquote = ''
      self.in_quote = 0
    
    
    else:
    
    
      self.thisquote = self.thisquote + '}'
  
    
    defcharacters
        
  (self, ch):
    
    
    if

         self.in_quote:
      self.thisquote = self.thisquote + ch
    
    if
         __name__ == '__main__':
  parser = xml.sax.make_parser()
  handler = QuotationHandler()
  parser.setContentHandler(handler)
  parser.parse("sample.xml")

与 xmllib 相比,上述示例中要注意两件小事: .parse() 方法处理整个流或字符串,所以不必为语法分析器创建循环; .parse() 同样能灵活地接收一个文件名、一个文件对象,或是众多的类文件对象(一些具有 .read() 方式)。

包:DOM

DOM 是一种 XML 文档的高级树型表示。该模型并非只针对 Python,而是一种普通 XML 模型(请参阅 参考资料以获取进一步信息)。Python 的 DOM 包是基于 SAX 构建的,并且包括在 Python 2.0 的标准 XML 支持里。由于篇幅所限,没有将代码示例加到本文中,但在 XML-SIG 的 "Python/XML HOWTO" 中给出了一个极好的总体描述:

    文档对象模型为 XML 文档指定了树型表示。顶级文档实例是树的根,它只有一个子代,即顶级元素实例;这个元素有表示内容和子元素的子节点,他们也可以有子代,以此类推。定义的函数允许随意遍历结果树,访问元素和属性值,插入和删除节点,以及将树转换回 XML。

    DOM 可以用于修改 XML 文档,因为可以创建一棵 DOM 树,通过添加新节点和来回移动子树来修改这棵树,然后生成一个新的 XML 文档作为输出。您也可以自己构造一棵 DOM 树,然后将它转换成 XML;用这种方法生成 XML 输出比仅将 <tag1>...</tag1> 写入文件的方法更灵活。

使用 xml.dom 模块的语法与早期的文章相比有了一些变动。Python 2.0 中自带的 DOM 实现被称为 xml.dom.minidom ,并提供轻量级和小型版本的 DOM。显然,完整的 XML-SIG 的 DOM 中有些试验性的特性并未被放入 xml.dom.minidom 中,但大家并不会注意到这一点。

生成 DOM 对象很简单;只需:
清单 4: 在 XML 文件中创建 Python DOM 对象

from
         xml.dom.minidom 
    
    import

         parse, parseString
dom1 = parse('mydata.xml') 
    
    # parse an XML file by name

使用 DOM 对象是种非常直接的 OOP 模式的工作。然而,经常在无法立刻简单区分的层级(除了循环列举)中碰到许多类似清单的属性。例如,以下是一段普通的 DOM Python 代码片断:
清单 5: 通过 Python DOM 节点对象的迭代

for
         node 
    
    in
         dom_node.childNodes:
  
    
    if

         node.nodeName == '#text':   
    
    # PCDATA is a kind of node,
    PCDATA = node.nodeValue    
    
    # but not a new subtag
     
     
     elif

         node.nodeName == 'spam':
    spam_node_list.append(node) 
    
    # Create list of <spam> nodes

Python 标准说明文档中有一些更详细的 DOM 示例。我的早期文章中有关使用 DOM 对象的示例(请参阅 参考资料)指出的方向仍然是正确的,但是文章发布后至今,一些方法和属性名称以更改,因此请查阅一下 Python 的说明文档。

模块: pyxie

pyxie 模块是在 Python 标准 XML 支持之上构建的,它为 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_pickle 和 xml_objectify

我自行开发了处理 XML 的高级模块,称为 xml_pickle 和 xml_objectify 。我还在其它地方写过许多类似模块(请参阅 参考资料),在此不必做过多的介绍。当你“用 Python 思考”而不是“用 XML 思考”时,这些模块非常有用。特别是 xml_objectify 自身对程序员隐藏了几乎所有的 XML 线索,使您在程序中充分使用 Python “原始”对象。实际的 XML 数据格式几乎被抽象得不可见。同样, xml_pickle 使 Python 程序员以“原始” Python 对象开始,该对象的数据可以来源于任何源代码,然后把它们(连续地)放入其他用户以后可能需要的 XML 格式。

Python 相关文章推荐
python使用多线程不断刷新网页的方法
Mar 31 Python
Fiddler如何抓取手机APP数据包
Jan 22 Python
Python用list或dict字段模式读取文件的方法
Jan 10 Python
用TensorFlow实现lasso回归和岭回归算法的示例
May 02 Python
python:print格式化输出到文件的实例
May 14 Python
Pycharm 设置自定义背景颜色的图文教程
May 23 Python
python实现比较文件内容异同
Jun 22 Python
对python 匹配字符串开头和结尾的方法详解
Oct 27 Python
Python实现带参数的用户验证功能装饰器示例
Dec 14 Python
Django配置MySQL数据库的完整步骤
Sep 07 Python
Python 中使用 PyMySQL模块操作数据库的方法
Nov 10 Python
如何使用python3获取当前路径及os.path.dirname的使用
Dec 13 Python
Python中的模块和包概念介绍
Apr 13 #Python
Python多线程编程简单介绍
Apr 13 #Python
Python中的面向对象编程详解(下)
Apr 13 #Python
简单介绍利用TK在Python下进行GUI编程的教程
Apr 13 #Python
Python中的面向对象编程详解(上)
Apr 13 #Python
进一步理解Python中的函数编程
Apr 13 #Python
Python中的异常处理简明介绍
Apr 13 #Python
You might like
《星际争霸2》终章已出 RTS时代宣告终结
2017/02/07 星际争霸
php+mysql开源XNA 聚合程序发布 下载
2007/07/13 PHP
php安全开发 添加随机字符串验证,防止伪造跨站请求
2013/02/14 PHP
php的SimpleXML方法读写XML接口文件实例解析
2014/06/16 PHP
PHP实现ASCII码与字符串相互转换的方法
2017/04/29 PHP
PHP删除字符串中非字母数字字符方法总结
2019/01/20 PHP
详解new function(){}和function(){}() 区别分析
2008/03/22 Javascript
一些相见恨晚的 JavaScript 技巧
2010/04/25 Javascript
js当一个变量为函数时 应该注意的一点细节小结
2011/12/29 Javascript
js字符串转换成数字与数字转换成字符串的实现方法
2014/01/08 Javascript
jQuery中hide()方法用法实例
2014/12/24 Javascript
jQuery扩展实现text提示还能输入多少字节的方法
2016/11/28 Javascript
详解webpack 配合babel 将es6转成es5 超简单实例
2017/05/02 Javascript
Angular.js中$resource高大上的数据交互详解
2017/07/30 Javascript
jQuery使用bind函数实现绑定多个事件的方法
2017/10/11 jQuery
基于react后端渲染模板引擎noox发布使用
2018/01/11 Javascript
vue实现引入本地json的方法分析
2018/07/12 Javascript
基于vue实现一个禅道主页拖拽效果
2019/05/27 Javascript
Vue数据绑定实例写法
2019/08/06 Javascript
JS端基于download.js实现图片、视频时直接下载而不是打开预览
2020/05/09 Javascript
如何通过JS实现日历简单算法
2020/10/14 Javascript
python程序封装为win32服务的方法
2021/03/07 Python
对python的bytes类型数据split分割切片方法
2018/12/04 Python
Python基于numpy模块实现回归预测
2020/05/14 Python
Python-openCV开运算实例
2020/07/05 Python
python3.8动态人脸识别的实现示例
2020/09/21 Python
python中zip()函数遍历多个列表方法
2021/02/18 Python
澳大利亚快时尚鞋类市场:Billini
2018/05/20 全球购物
New Balance比利时官方网站:购买鞋子和服装
2021/01/15 全球购物
Linux的主要特性
2016/09/03 面试题
《水上飞机》教学反思
2014/04/10 职场文书
公司自我介绍演讲稿
2014/08/21 职场文书
2014年职称评定工作总结
2014/11/26 职场文书
工程移交协议书
2016/03/24 职场文书
JavaScript组合继承详解
2021/11/07 Javascript
解决spring.thymeleaf.cache=false不起作用的问题
2022/06/10 Java/Android