2008-10-10 14 views
64

Python hat mehrere Möglichkeiten, XML zu analysieren ...XML-Parsing - ElementTree vs SAX und DOM

ich die Grundlagen verstehen mit SAX parsen. Es funktioniert als Stream-Parser mit einer ereignisgesteuerten API.

Ich verstehe die DOM Parser auch. Es liest das XML in den Speicher und konvertiert es in Objekte, auf die mit Python zugegriffen werden kann.

Generell war es leicht, zwischen den 2 je nach wählen, was Sie tun mußten, Speicherbeschränkungen, Leistung etc.

(hoffentlich bin ich soweit in Ordnung).

Seit Python 2.5 haben wir auch ElementTree. Wie ist das mit DOM und SAX zu vergleichen? Womit ist es ähnlicher? Warum ist es besser als die vorherigen Parser?

Antwort

60

ElementTree ist viel einfacher zu verwenden, da es eine XML-Struktur (im Grunde genommen) als eine Struktur von Listen darstellt und Attribute als Wörterbücher dargestellt werden.

ElementTree benötigt viel weniger Speicher für XML-Bäume als DOM (und ist daher schneller) und der Parsing-Overhead über iterparse ist vergleichbar mit SAX. Darüber hinaus gibt iterparse Teilstrukturen zurück, und Sie können die Speichernutzung während des Parsens konstant halten, indem Sie die Strukturen verwerfen, sobald Sie sie verarbeiten.

ElementTree, wie in Python 2.5, hat nur ein kleines Feature-Set im Vergleich zu vollwertigen XML-Bibliotheken, aber es ist genug für viele Anwendungen. Wenn Sie einen validierenden Parser oder vollständige XPath-Unterstützung benötigen, ist lxml der richtige Weg. Lange Zeit war es ziemlich instabil, aber seit 2.1 hatte ich keine Probleme damit.

ElementTree weicht von DOM ab, wobei Knoten Zugriff auf ihre übergeordneten und gleichgeordneten Elemente haben. Die Handhabung von tatsächlichen Dokumenten anstelle von Datenspeichern ist ebenfalls ein wenig umständlich, da Textknoten nicht als tatsächliche Knoten behandelt werden. In der XML-Snippet

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

Die Zeichenfolge test wird b die sogenannte tail von Element sein.

Im Allgemeinen empfehle ich ElementTree als Standard für alle XML-Verarbeitung mit Python und DOM oder SAX als Lösungen für bestimmte Probleme.

+0

Vielen Dank, dass Sie die beiden folgenden Vorbehalte erwähnt haben! (Ich brauche beide in meinem Projekt.) "XPath-Unterstützung ... ElementTree weicht von DOM ab, wo Knoten Zugriff auf ihre Eltern und Geschwister haben." –

8

ElementTree parse() ist wie DOM, während iterparse() wie SAX ist. Meiner Meinung nach ist ElementTree besser als DOM und SAX, da es einfacher mit API zu arbeiten ist.

+0

Auch finde ich, dass ich die reale Struktur will. –

+0

Ein serieller Parser ist oft gut genug für einfaches Parsen. Ich begann Python mit Saxophon und wechselte erst zum Minidom, als meine Bedürfnisse für Saxophon zu komplex wurden. Ich sollte hinzufügen, dass ich ElementTree noch nicht benutzt habe, da es anscheinend nicht genug mehr Funktionalität bietet, um meinen Code dorthin zu portieren. – giltay

6

ElementTree hat mehr Python-API. Es ist jetzt auch in der Standardbibliothek, so dass es die Abhängigkeiten reduziert.

Ich bevorzuge eigentlich lxml wie es API wie ElementTree hat, hat aber auch schöne zusätzliche Funktionen und funktioniert gut.

11

Minimal DOM-Implementierung:

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

Python liefert eine vollständige, W3C-Standard-Implementierung von XML-DOM (xml.dom) und eine minimale, xml.dom.minidom. Dieser letztere ist einfacher und kleiner als die vollständige Implementierung. Aus einer "Parsing-Perspektive" hat es jedoch alle Vor- und Nachteile des Standard-DOM - d. H. Es lädt alles im Speicher.

eine einfache XML-Datei unter Berücksichtigung

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

Ein möglicher Python-Parser minidom ist:

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 

Beachten Sie, dass xml.parsers.expat ist eine Python-Schnittstelle zum Expat nicht validierender XML-Parser (docs.python.org/2/library/pyexpat.html).

Die xml.dom Paket liefert auch die Ausnahmeklasse DOMException, aber es ist nicht in minidom supperted!

Der ElementTree XML API:

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

ElementTree ist viel einfacher zu bedienen und erfordert weniger Speicher als XML DOM. Außerdem ist eine C-Implementierung verfügbar (xml.etree.cElementTree).

Ein möglicher Python-Parser ElementTree verwendet, ist: nicht eine Reihe von Veranstaltungen

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

Danke! Sehr hilfreich. Ich bin nicht sicher genug, um es zu bearbeiten, aber ich denke (a) das andere ist nicht hilfreich, da es schließlich keine gibt: http://stackoverflow.com/questions/855759/python-try-else; (b) eine einfache Gehaltserhöhung würde mehr als nur e erhalten: http://stackoverflow.com/questions/11420464/python-catch-exceptions-inside-a-class –

+0

In Bezug auf Punkt (a), ja. Es gibt keine endgültige Aussage, nur weil es in meinem Beispiel keine Notwendigkeit gab. Ich kann mich nicht erinnern, warum ich es gesagt habe. Auch wenn es in diesem Fall nutzlos ist, ist die else-Anweisung nicht syntaktisch falsch. –

+0

In Bezug auf Punkt (b) könnte es so sein. Ich denke jedoch (in meinem Beispiel) ist dies ein wenig außerhalb des Geltungsbereichs. In der Tat sollte der Code nur ein einfaches Beispiel für das XML-Parsing sein ... –