Python解析XML与生成迭代器 Jun, 2015

编程 编程语言

这次来看看Python解析XML与生成迭代器。

迭代器

使用yield操作符可以使一个函数变成迭代器。如下一段测试代码:

def genTest(n):
  print 1
  print 2
  for i in range(3,n+1):
    yield i
  print n+1
  print n+2

if __name__ == '__main__':
  for i in genTest(5):
    print i

输出如下:

1
2
3
4
5
6
7

可以看出第一次调用genTest()时执行了1,2位置的代码。 之后yield将i返回给caller的i,然后再次调用时继续从genTest上次yield之后的代码执行,直至最后return停止,迭代结束。

Python解析XML

Python解析XML有许多种方法,它们各有特色。

ElementTree

ElementTree是python xml解析的一种轻量级实现。 它将XMl文件读取到内存中以一棵树的形式存储。 它速度快且方便使用,但是不能读取不规范的XMl文件,并且会一次将XML文件解析入内存。 因此适合解析一些小型的XML文件。 cElementTree是它的一个C优化过的版本。

示例代码如下:

def readXMLET(filename):
  try:
    import xml.etree.cElementTree as ET
  except ImportError:
    import xml.etree.ElementTree as ET
  tree = ET.ElementTree(file=filename)
  print 'read finish!'
  root = tree.getroot()
  for child in root:
    yield child.tag, child.attrib

BeautifulSoup Parser

刚提到ElementTree不能读取不规范的XML,BeautifulSoup Parser则可以,它试图修复XML中的不规范成分。 但是由于使用了正则表达式,相对的它的效率会低于ElementTree。

示例代码如下:

def readXMLlxml(filename):
  from lxml.html import soupparser

  tree = soupparser.parse(filename)
  root = tree.getroot()
  for child in root:
    yield child.tag, child.attrib

SAX

前面两种方法都是将XML一次以一棵树的形式读入内存中。 若是XML文件较大的话这种方式会非常慢且消耗内存。 SAX则是以一种异步的方式处理它遇到的XML标签,而不是将其一次全部解析,因此比较适合体积很大的XML文件。 但是它不会记得之前处理过的标签算是一个缺点。

你需要继承xml.sax.ContentHandler类,然后在解析的时候将这个类的实例传入即可。

这个类有如下方法:

  • characters(content)方法:调用时机为从行开始,遇到标签之前,存在字符,content的值为这些字符串;从一个标签,遇到下一个标签之前, 存在字符,content的值为这些字符串;从一个标签,遇到行结束符之前,存在字符,content的值为这些字符串。标签可以是开始标签,也可以是结束标签。

  • startDocument()方法:文档启动的时候调用。

  • endDocument()方法:解析器到达文档结尾时调用。

  • startElement(name, attrs)方法:遇到XML开始标签时调用,name是标签的名字,attrs是标签的属性值字典。

  • endElement(name)方法:遇到XML结束标签时调用。

示例代码如下:

class resHandler(xml.sax.ContentHandler):
  def __init__(self):
    self.count = 0

  def startElement(self, tag, attrib):
    if tag == 'doc':
      self.count += 1
      if self.count % 1000 == 0:
        print self.count
      doc = {
        TAG:tag,
        TITLE:attrib[TITLE],
        ANCHOR:attrib[ANCHOR],
        H1:attrib[H1],
        PATH:attrib[PATH],
        PAGERANK:attrib[PAGERANK]
      }
      print doc

def readXMLSAX(filename):
  parser = xml.sax.make_parser()
  parser.setContentHandler(resHandler())
  parser.parse(filename)