2008-10-10 20 views
64

Python tiene varias maneras de analizar XML ...análisis XML - elementtree vs SAX y DOM

entiendo los conceptos básicos de análisis sintáctico con SAX. Funciona como un analizador de flujo, con una API controlada por eventos.

Entiendo el DOM analizador también. Lee el XML en memoria y lo convierte en objetos a los que se puede acceder con Python.

En términos generales, era fácil elegir entre el 2 dependiendo de lo que tenía que hacer, las limitaciones de memoria, rendimiento, etc.

(esperemos que estoy en lo cierto hasta ahora).

Desde Python 2.5, también tenemos ElementTree. ¿Cómo se compara esto con DOM y SAX? ¿A qué se parece más? ¿Por qué es mejor que los analizadores sintácticos anteriores?

Respuesta

60

ElementTree es mucho más fácil de usar, ya que representa un árbol XML (básicamente) como una estructura de listas, y los atributos se representan como diccionarios.

ElementTree necesita mucha menos memoria para los árboles XML que DOM (y por lo tanto es más rápido), y la tara de análisis a través de iterparse es comparable a SAX. Además, iterparse devuelve estructuras parciales, y puede mantener el uso de la memoria constante durante el análisis descartando las estructuras tan pronto como las procese.

ElementTree, como en Python 2.5, tiene solo un pequeño conjunto de características en comparación con las bibliotecas de XML completas, pero es suficiente para muchas aplicaciones. Si necesita un analizador de validación o soporte completo de XPath, lxml es el camino a seguir. Durante mucho tiempo, solía ser bastante inestable, pero no he tenido ningún problema con él desde 2.1.

ElementTree se desvía de DOM, donde los nodos tienen acceso a sus padres y hermanos. Manejar documentos reales en lugar de almacenar datos también es un poco engorroso, porque los nodos de texto no se tratan como nodos reales. En el fragmento de código XML

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

La cadena test será el denominado tail del elemento b.

En general, recomiendo ElementTree como predeterminado para todo el procesamiento XML con Python, y DOM o SAX como soluciones para problemas específicos.

+0

¡Gracias por mencionar las siguientes advertencias! (Resulta que necesito ambos en mi proyecto). "Soporte de XPath ... ElementTree se desvía de DOM, donde los nodos tienen acceso a sus padres y hermanos". –

8

ElementTree's parse() es como DOM, mientras que iterparse() es como SAX. En mi opinión, ElementTree es mejor que DOM y SAX, ya que proporciona API más fácil de trabajar.

+0

Además, me parece que quiero que la estructura real, no una serie de eventos. –

+0

Un analizador en serie a menudo es lo suficientemente bueno para un análisis simple. Inicié Python usando sax, y solo cambié a minidom cuando mis necesidades se volvieron demasiado complejas para Saxo. Debo agregar que aún no he usado ElementTree, ya que no parece ofrecer suficiente funcionalidad para que le transfiera mi código. – giltay

6

ElementTree tiene más API pythonic. También está en la biblioteca estándar ahora, por lo que usarlo reduce las dependencias.

En realidad prefiero lxml ya que tiene API como ElementTree, pero también tiene buenas características adicionales y funciona bien.

11

Mínimo implementación DOM:

Enlace: http://docs.python.org/2/library/xml.dom.minidom.html#module-xml.dom.minidom

Python proporciona una implementación estándar del W3C-llena de DOM XML (XML .dom) y uno mínimo, xml.dom.minidom. Este último es más simple y más pequeño que la implementación completa. Sin embargo, desde una "perspectiva de análisis", tiene todos los pros y contras del DOM estándar, es decir, carga todo en la memoria.

Considerando un archivo XML básica:

<?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> 

Una posible analizador Python usando minidom es:

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 

Tenga en cuenta que xml.parsers.expat es una interfaz de Python para los expatriados analizador XML no validador (docs.python.org/2/library/pyexpat.html).

Los xml.dom paquete proporciona también la clase de excepción DOMException, pero no se supperted en minidom!

El elementtree API XML:

Enlace: http://docs.python.org/2/library/xml.etree.elementtree.html

elementtree es mucho más fácil de usar y requiere menos memoria que DOM XML. Además, está disponible una implementación de C (xml.etree.cElementTree).

Una posible analizador Python usando elementtree es:

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

Gracias! Muy útil. No estoy seguro de poder editarlo, pero creo que (a) el otro no es útil, ya que finalmente no existe: http://stackoverflow.com/questions/855759/python-try-else; (b) un aumento simple preservaría más que elevar e: http://stackoverflow.com/questions/11420464/python-catch-exceptions-inside-a-class –

+0

Con respecto al punto (a), sí. No hay una declaración final simplemente porque, en mi ejemplo, no hubo necesidad. No recuerdo por qué lo dije. Sin embargo, incluso si fuera inútil en este caso, tener la instrucción else no es sintácticamente incorrecta. –

+0

Con respecto al punto (b), podría ser así. Sin embargo, creo (en mi ejemplo), esto está un poco fuera de alcance. De hecho, el código pretendía ser solo un simple ejemplo de análisis XML ... –

Cuestiones relacionadas