Разбор XML - ElementTree vs SAX и DOM

Python имеет несколько способов анализа XML...

Я понимаю самые основы синтаксического анализа SAX. Он функционирует как парсер потока, с управляемым событиями API.

Я понимаю синтаксический анализатор DOM. Он читает XML в памяти и закрывает его для объектов, к которым можно получить доступ с помощью Python.

Вообще говоря, было легко выбирать между 2 в зависимости от того, что вам нужно было делать, ограничений памяти, производительности и т.д.

(надеюсь, я до сих пор прав).

С Python 2.5 у нас также есть ElementTree. Как это соотносится с DOM и SAX? Что это больше похоже на? Почему это лучше, чем предыдущие парсеры?

Ответ 1

ElementTree гораздо проще в использовании, поскольку он представляет дерево XML (в основном) как структуру списков, а атрибуты представлены в виде словарей.

ElementTree требует гораздо меньше памяти для деревьев XML, чем DOM (и, следовательно, быстрее), а служебные данные синтаксического анализа через iterparse сопоставимы с SAX. Кроме того, iterparse возвращает частичные структуры, и вы можете сохранить постоянное использование памяти во время синтаксического анализа, отбросив структуры сразу после их обработки.

ElementTree, как и в Python 2.5, имеет только небольшой набор функций по сравнению с полномасштабными библиотеками XML, но этого достаточно для многих приложений. Если вам нужен проверочный синтаксический анализатор или полная поддержка XPath, lxml - это путь. Долгое время он был довольно неустойчивым, но с тех пор у меня не было никаких проблем с 2.1.

ElementTree отклоняется от DOM, где узлы имеют доступ к своим родителям и братьям и сестрам. Обработка фактических документов, а не хранилищ данных, также немного громоздка, поскольку текстовые узлы не рассматриваются как фактические узлы. В фрагменте XML

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

Строка test будет так называемым tail элемента b.

В общем, я рекомендую ElementTree по умолчанию для всей обработки XML с помощью Python и DOM или SAX в качестве решений для конкретных проблем.

Ответ 2

Минимальная реализация DOM:

Ссылка: http://docs.python.org/2/library/xml.dom.minidom.html#module-xml.dom.minidom

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>

Возможный парсер 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 - это интерфейс Python для не проверяющего XML-анализатора Expat (docs.python.org/2/library/pyexpat.html).

Пакет xml.dom также предоставляет класс DOMException класса исключений, но он не утихает в мини-классе!

XML-интерфейс ElementTree:

Ссылка: http://docs.python.org/2/library/xml.etree.elementtree.html

ElementTree намного проще в использовании и требует меньше памяти, чем XML DOM. Кроме того, доступна реализация C (xml.etree.cElementTree).

Возможный парсер Python с использованием ElementTree:

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

Ответ 3

ElementTree parse() подобен DOM, тогда как iterparse() похож на SAX. На мой взгляд, ElementTree лучше, чем DOM и SAX, поскольку он упрощает работу с API.

Ответ 4

ElementTree имеет больше pythonic API. Теперь он также находится в стандартной библиотеке, поэтому его использование уменьшает зависимости.

Я действительно предпочитаю lxml, поскольку у него есть API, такой как ElementTree, но он также обладает хорошими дополнительными функциями и хорошо работает.