【问题标题】:XML parsing - ElementTree vs SAX and DOMXML 解析 - ElementTree vs SAX 和 DOM
【发布时间】:2010-09-16 14:43:54
【问题描述】:

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

我了解使用 SAX 进行解析的基础知识。它用作流解析器,具有事件驱动的 API。

我也了解 DOM 解析器。它将 XML 读入内存并将其转换为 Python 可以访问的对象。

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

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

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

【问题讨论】:

    标签: python xml dom sax elementtree


    【解决方案1】:

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

    【讨论】:

    • 另外,我发现我想要的是真实的结构,而不是一系列事件。
    • 串行解析器通常足以进行简单的解析。我使用 sax 开始 Python,只有当我的需求变得对 sax 来说过于复杂时才切换到 minidom。我应该补充一点,我还没有使用过 ElementTree,因为它似乎没有提供足够多的功能让我将代码移植到它。
    【解决方案2】:

    ElementTree 有更多 Pythonic API。它现在也在标准库中,因此使用它可以减少依赖关系。

    我实际上更喜欢lxml,因为它有类似 ElementTree 的 API,但也有很好的附加功能并且性能很好。

    【讨论】:

      【解决方案3】:

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

      ElementTree 比 DOM 需要更少的内存用于 XML 树(因此更快),并且通过 iterparse 的解析开销与 SAX 相当。此外,iterparse 返回部分结构,您可以在解析过程中通过在处理它们时立即丢弃这些结构来保持内存使用量不变。

      ElementTree 与 Python 2.5 一样,与成熟的 XML 库相比只有很小的功能集,但对于许多应用程序来说已经足够了。如果您需要验证解析器或完整的 XPath 支持,lxml 是您的最佳选择。很长一段时间,它曾经很不稳定,但是从2.1开始我没有遇到任何问题。

      ElementTree 与 DOM 不同,其中节点可以访问其父级和兄弟级。处理实际文档而不是数据存储也有点麻烦,因为文本节点不被视为实际节点。在 XML sn-p

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

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

      一般来说,我推荐 ElementTree 作为所有使用 Python 处理 XML 的默认设置,而 DOM 或 SAX 作为特定问题的解决方案。

      【讨论】:

      • 感谢您提及以下两个警告! (我碰巧在我的项目中需要这两者。)“XPath 支持...... ElementTree 偏离了 DOM,其中节点可以访问它们的父级和兄弟级。”
      • ElementTree 还有一个问题,就是文本内容被当作前一个Node的属性,而不是自己的Node。所以在 "

        The brown dog

        " 中,

        元素有 1 个子元素,而不是 3 个。"The" 是

        上的属性,而 "dog"是 上的一个属性(甚至不是相同的属性——在

        结束之后也可能有文本)。如果您使用 HTML、CSS 或其他大多数与文档有关的东西,几乎所有关于树、上下文、路径和搜索的工作方式都与您习惯的方式不同。

      • @JonCoombs ElementTree 支持 xpath as said in docs
      【解决方案4】:

      最小的 DOM 实现:

      Link.

      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,但在minidom 中不支持它!

      ElementTree XML API:

      Link.

      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
      

      【讨论】:

      • 谢谢!非常有帮助。我不确定是否可以编辑它,但我认为 (a) else 没有帮助,因为没有 finally:stackoverflow.com/questions/855759/python-try-else; (b) 一个简单的加注将比加注 e 保留更多:stackoverflow.com/questions/11420464/…
      • 关于 (a) 点,是的。没有 finally 语句仅仅是因为在我的示例中没有必要。我不记得我为什么放了它。但是,即使在这种情况下没有用,使用 else 语句在语法上也没有错。
      • 关于(b)点,可能是这样。但是,我认为(在我的示例中)这有点超出范围。事实上,代码只是一个简单的 XML 解析示例......
      • 哦,我并不是说其中任何一个都是“错误的”;只是为了其他可能出现并复制/粘贴的人而建议的编辑。
      • 请注意,cElementTree 自 Python 3.3 起已弃用
      猜你喜欢
      • 2014-06-30
      • 1970-01-01
      • 2012-07-03
      • 2012-07-28
      • 2020-01-17
      • 2021-02-08
      • 2012-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多