XML解析-ElementTree与SAX和DOM


74

Python有几种解析XML的方法...

我了解使用SAX解析的基本知识。它具有事件驱动的API,可充当流解析器。

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

一般来说,根据您需要执行的操作,内存限制,性能等,在这两者之间进行选择很容易。

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

从Python 2.5开始,我们还有ElementTree。与DOM和SAX相比如何?哪个更相似?为什么比以前的解析器更好?

Answers:


72

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

ElementTree的XML树所需的内存比DOM少得多(因此更快),并且via的解析开销iterparse与SAX相当。此外,iterparse返回部分结构,并且您可以在解析过程中通过在处理结构后立即将其丢弃来使内存使用保持恒定。

与成熟的XML库相比,Python 2.5中的ElementTree仅具有很小的功能集,但对于许多应用程序来说已经足够了。如果您需要验证解析器或完整的XPath支持,则可以使用lxml。很长一段时间以来,它一直很不稳定,但是自2.1以来我一直没有遇到任何问题。

ElementTree不同于DOM,在DOM中,节点可以访问其父级和同级。处理实际文档而不是数据存储也很麻烦,因为文本节点不被视为实际节点。在XML代码段中

<a>This is <b>a</b> test</a>

字符串test将是所谓tail的element b

通常,我建议使用ElementTree作为使用Python进行的所有XML处理的默认设置,并建议使用DOM或SAX作为特定问题的解决方案。


2
感谢您提到以下两个警告!(在我的项目中,我碰巧需要两者。)“ XPath支持... ElementTree与DOM有所不同,在DOM中,节点可以访问其父级和同级。”
乔恩·库姆斯

1
ElementTree还存在一个问题,即文本内容被视为先前节点的属性,而不是其自身的节点。因此,在“ <p> <i>棕色</ i>狗</ p>”中,<p>元素有1个孩子,而不是3个。“ The”是<p>上的一个属性,而“ dog”是是<i>上的一个属性(甚至不是相同的属性-<p>结束后也可能有文本)。如果您使用HTML,CSS或大多数其他与文档相关的功能,则几乎所有与树,上下文,路径以及搜索有关的工作方式都与以往不同。
TextGeek

13

最小的DOM实现:

链接

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

考虑基本的XML文件:

<?xml version="1.0"?>
<catalog>
    <book isdn="xxx-1">
      <author>A1</author>
      <title>T1</title>
    </book>
    <book isdn="xxx-2">
      <author>A2</author>
      <title>T2</title>
    </book>
</catalog>

使用minidom的可能的Python解析器是:

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,但它不是supperted在minidom命名

ElementTree XML API:

链接

ElementTree易于使用,并且比XML DOM需要更少的内存。此外,可以使用C实现(xml.etree.cElementTree)。

使用ElementTree的可能的Python解析器是:

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

2
谢谢!很有帮助。我不确定是否可以对其进行编辑,但是我认为(a)否则没有帮助,因为最终没有了:stackoverflow.com/questions/855759/python-try-else ; :(B)普通加薪将保持超过加薪ë stackoverflow.com/questions/11420464/...
乔恩·库姆斯

关于(a)点,是的。没有final语句只是因为在我的示例中没有必要。我不记得为什么这么做了。但是,即使在这种情况下没有用,使用else语句在语法上也不是错误的。
Paolo Rovelli 2014年

关于(b)点,可能是这样。但是,我认为(在我的示例中)这有点超出范围。实际上,该代码仅是XML解析的简单示例……
Paolo Rovelli 2014年

1
哦,我不是说任何一个“错误”。仅推荐一些建议的编辑内容,以免其他人复制和粘贴。
乔恩·库姆斯

5
请注意,自Python 3.3起不推荐使用cElementTree
gerrit 2015年

8

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

我实际上更喜欢lxml,因为它具有像ElementTree这样的API,但是还具有不错的附加功能并且运行良好。


7

ElementTree的parse()就像DOM,而iterparse()就像SAX。在我看来,ElementTree比DOM和SAX更好,因为它提供了更易于使用的API。


另外,我发现我想要的是真实的结构,而不是一系列事件。
S.Lott

1
串行解析器通常足以进行简单的解析。我使用sax启动Python,仅在对sax变得过于复杂时才切换到最小化。我应该补充一点,我还没有使用ElementTree,因为它似乎没有为我提供足够的更多功能来将代码移植到其中。
giltay
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.