关于python:XML解析 – ElementTree vs SAX和DOM

XML parsing - ElementTree vs SAX and DOM

python有几种解析XML的方法…

我了解使用SAX解析的基本知识。它使用事件驱动的API作为流解析器。

我也理解DOM解析器。它将XML读取到内存中,并将其转换为可以用Python访问的对象。

一般来说,根据需要做的事情、内存限制、性能等,在两者之间进行选择是很容易的。

(希望到目前为止我是正确的。)

自从python 2.5以来,我们也有elementtree。这与dom和sax相比如何?它与哪个更相似?为什么它比以前的解析器更好?


ElementTree更易于使用,因为它将XML树(基本上)表示为列表结构,属性表示为字典。

与DOM相比,elementtree需要的XML树内存要少得多(因此速度更快),并且通过iterparse的解析开销与SAX相当。另外,iterparse返回部分结构,您可以在解析过程中保持内存使用不变,方法是在处理结构后立即丢弃这些结构。

与完整的XML库相比,与Python2.5中的elementTree只有一个很小的特性集,但对于许多应用程序来说已经足够了。如果您需要一个验证解析器或完整的XPath支持,那么LXML就是解决问题的方法。很长一段时间以来,它一直很不稳定,但我从2.1开始就没有遇到任何问题。

elementtree与dom不同,后者中的节点可以访问其父节点和同级节点。处理实际文档而不是数据存储也有点麻烦,因为文本节点不被视为实际节点。在XML代码段中

1
This is a test

字符串test将是元素b的所谓tail

一般来说,我建议将elementtree作为使用python进行所有XML处理的默认值,并将dom或sax作为特定问题的解决方案。


最小DOM实现:

链接。

python提供了完整的W3C标准的XML DOM(xml.dom)实现和最小的XML.dom.minidom实现。后者比完整的实现更简单、更小。但是,从"解析角度"来看,它具有标准DOM的所有优点和缺点,即它将所有内容加载到内存中。

考虑到基本的XML文件:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<catalog>
    <book isdn="xxx-1">
      A1</author>
      T1
    </book>
    <book isdn="xxx-2">
      A2</author>
      T2
    </book>
</catalog>

使用minidom的一个可能的python解析器是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import os
from xml.dom import minidom
from xml.parsers.expat import ExpatError

#-------- Select the XML file: --------#
#Current file name and directory:
curpath = os.path.dirname( os.path.realpath(__file__) )
filename = os.path.join(curpath,"sample.xml")
#print"Filename: %s" % (filename)

#-------- Parse the XML file: --------#
try:
    #Parse the given XML file:
    xmldoc = minidom.parse(filepath)
except ExpatError as e:
    print"[XML] Error (line %d): %d" % (e.lineno, e.code)
    print"[XML] Offset: %d" % (e.offset)
    raise e
except IOError as e:
    print"[IO] I/O Error %d: %s" % (e.errno, e.strerror)
    raise e
else:
    catalog = xmldoc.documentElement
    books = catalog.getElementsByTagName("book")

    for book in books:
        print book.getAttribute('isdn')
        print book.getElementsByTagName('author')[0].firstChild.data
        print book.getElementsByTagName('title')[0].firstChild.data

请注意,xml.parsers.expat是expat非验证XML解析器(docs.python.org/2/library/pyexpat.html)的python接口。

xml.dom包还提供异常类domException,但在minidom中不支持它!

元素树XML API:

链接。

elementtree更易于使用,它比XMLDOM需要更少的内存。此外,还提供了C实现(xml.etree.CelementTree)。

使用elementtree的一个可能的python解析器是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import os
from xml.etree import cElementTree  # C implementation of xml.etree.ElementTree
from xml.parsers.expat import ExpatError  # XML formatting errors

#-------- Select the XML file: --------#
#Current file name and directory:
curpath = os.path.dirname( os.path.realpath(__file__) )
filename = os.path.join(curpath,"sample.xml")
#print"Filename: %s" % (filename)

#-------- Parse the XML file: --------#
try:
    #Parse the given XML file:
    tree = cElementTree.parse(filename)
except ExpatError as e:
    print"[XML] Error (line %d): %d" % (e.lineno, e.code)
    print"[XML] Offset: %d" % (e.offset)
    raise e
except IOError as e:
    print"[XML] I/O Error %d: %s" % (e.errno, e.strerror)
    raise e
else:
    catalogue = tree.getroot()

    for book in catalogue:
        print book.attrib.get("isdn")
        print book.find('author').text
        print book.find('title').text


elementTree的parse()类似于dom,而iterparse()类似于sax。在我看来,elementtree比dom和sax更好,因为它提供了更容易使用的API。


elementtree有更多的pythonic API。它现在也在标准库中,因此使用它可以减少依赖性。

实际上,我更喜欢LXML,因为它有类似API的elementtree,但也有很好的附加特性和良好的性能。