Analisi XML - ElementTree vs SAX e DOM
-
08-07-2019 - |
Domanda
Python ha diversi modi per analizzare XML ...
Comprendo le basi dell'analisi con SAX . Funziona come un parser di flusso, con un'API guidata dagli eventi.
Comprendo anche il parser DOM . Legge l'XML in memoria e lo converte in oggetti a cui è possibile accedere con Python.
In generale, era facile scegliere tra i due a seconda di cosa dovevi fare, vincoli di memoria, prestazioni, ecc.
(Spero di aver ragione fino ad ora.)
Da Python 2.5, abbiamo anche ElementTree . Come si confronta con DOM e SAX? A cosa è più simile? Perché è meglio dei precedenti parser?
Soluzione
ElementTree è molto più facile da usare, perché rappresenta un albero XML (sostanzialmente) come una struttura di elenchi e gli attributi sono rappresentati come dizionari.
ElementTree richiede molta meno memoria per gli alberi XML rispetto al DOM (e quindi è più veloce), e l'overhead di analisi tramite iterparse
è paragonabile a SAX. Inoltre, iterparse
restituisce strutture parziali e puoi mantenere costante l'uso della memoria durante l'analisi scartando le strutture non appena le elabori.
ElementTree, come in Python 2.5, ha solo un piccolo set di funzionalità rispetto alle librerie XML complete, ma è sufficiente per molte applicazioni. Se hai bisogno di un parser di convalida o di un supporto XPath completo, lxml è la strada da percorrere. Per molto tempo, era piuttosto instabile, ma non ho avuto problemi con esso dal 2.1.
ElementTree si discosta dal DOM, dove i nodi hanno accesso ai loro genitori e fratelli. Anche la gestione di documenti effettivi anziché di archivi di dati è un po 'complicata, poiché i nodi di testo non sono trattati come nodi effettivi. Nello snippet XML
<a>This is <b>a</b> test</a>
La stringa test
sarà la cosiddetta tail
dell'elemento b
.
In generale, consiglio ElementTree come predefinito per tutta l'elaborazione XML con Python e DOM o SAX come soluzioni per problemi specifici.
Altri suggerimenti
Implementazione DOM minima:
Link .
Python fornisce un'implementazione completa, standard W3C di XML DOM ( xml.dom ) e minima, xml.dom.minidom . Quest'ultimo è più semplice e più piccolo della piena implementazione. Tuttavia, dal punto di vista dell'analisi, ha tutti i vantaggi e gli svantaggi del DOM standard, ovvero carica tutto in memoria.
Considerando un file XML di base:
<?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>
Un possibile parser Python che utilizza minidom è:
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
Nota che xml.parsers.expat è un'interfaccia Python per il parser XML non validante Expat (docs.python.org/2/library/pyexpat.html).
Il pacchetto xml.dom fornisce anche la classe di eccezioni DOMException , ma non è supportata in minidom !
L'API XML ElementTree:
Link .
ElementTree è molto più facile da usare e richiede meno memoria del DOM XML. Inoltre, è disponibile un'implementazione C ( xml.etree.cElementTree ).
Un possibile parser Python che utilizza 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
L'analisi () di ElementTree è come DOM, mentre iterparse () è come SAX. A mio avviso, ElementTree è migliore di DOM e SAX in quanto fornisce API più facile da lavorare.
ElementTree ha più API pythonic. Ora è anche nella libreria standard, quindi l'utilizzo riduce le dipendenze.
In realtà preferisco lxml in quanto ha API come ElementTree, ma ha anche belle funzionalità aggiuntive e funziona bene.