2008-10-10 11 views
64

Python ma kilka sposobów analizowania XML ...analizowania XML - ElementTree vs SAX i DOM

Rozumiem Bardzo Podstawy parsowania z SAX. Działa jako parser strumienia z interfejsem API sterowanym zdarzeniami.

Rozumiem także parser DOM. Czyta XML w pamięci i przenosi go do obiektów, do których można uzyskać dostęp za pomocą Pythona.

Ogólnie mówiąc, łatwo było wybrać między 2 w zależności od tego, co trzeba było zrobić, ograniczenia pamięci, wydajność itd

(mam nadzieję, że się nie mylę do tej pory).

Od Pythona 2.5, mamy również ElementTree. Jak to porównać do DOM i SAX? Który jest bardziej podobny do? Dlaczego jest lepszy niż poprzednie parsery?

Odpowiedz

60

ElementTree jest znacznie łatwiejszy w użyciu, ponieważ reprezentuje drzewo XML (w zasadzie) jako strukturę list, a atrybuty są reprezentowane jako słowniki.

ElementTree potrzebuje o wiele mniej pamięci dla drzew XML niż DOM (a przez to jest szybszy), a obciążenie podczas analizowania za pomocą iterparse jest porównywalne do SAX. Ponadto, iterparse zwraca struktury częściowe i możesz zachować użycie pamięci na stałym poziomie podczas analizowania, odrzucając struktury natychmiast po ich przetworzeniu.

ElementTree, podobnie jak w Pythonie 2.5, ma tylko niewielki zestaw funkcji w porównaniu do pełnowymiarowych bibliotek XML, ale wystarcza dla wielu aplikacji. Jeśli potrzebujesz sprawdzania poprawności analizatora składni lub kompletnej obsługi XPath, lxml jest do zrobienia. Przez długi czas był dość niestabilny, ale nie miałem z nim żadnych problemów od 2.1.

ElementTree różni się od DOM, gdzie węzły mają dostęp do ich rodzica i rodzeństwa. Obsługa faktycznych dokumentów, a nie magazynów danych, jest również nieco kłopotliwa, ponieważ węzły tekstowe nie są traktowane jako rzeczywiste węzły. W XML snippet

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

Ciąg test będzie tzw tail elementu b.

Ogólnie, polecam ElementTree jako domyślny dla całego przetwarzania XML w Pythonie, a DOM lub SAX jako rozwiązania dla konkretnych problemów.

+0

Dziękujemy za podanie obu poniższych zastrzeżeń! (Potrzebuję obu w moim projekcie.) "Obsługa XPath ... ElementTree różni się od DOM, gdzie węzły mają dostęp do rodzica i rodzeństwa." –

8

Parse ElementTree() jest jak DOM, natomiast iterparse() jest jak SAX. Moim zdaniem ElementTree jest lepszy niż DOM i SAX, ponieważ zapewnia łatwiejszy w obsłudze interfejs API.

+0

Również uważam, że chcę rzeczywistą strukturę, a nie serii zdarzeń. –

+0

Parser szeregowy jest często wystarczająco dobry do prostego analizowania. Zacząłem Pythona używając sax i przerzuciłem się na minidom, kiedy moje potrzeby stały się zbyt skomplikowane dla sax. Powinienem dodać, że nie użyłem ElementTree, ponieważ wydaje mi się, że nie oferuje wystarczająco dużo więcej funkcji do przeniesienia mojego kodu do niego. – giltay

6

ElementTree ma więcej pythonic API. Jest również w standardowej bibliotece, więc używanie go zmniejsza zależności.

Właściwie wolę lxml ponieważ ma API jak ElementTree, ale ma również ładne dodatkowe funkcje i działa dobrze.

11

Minimal implementacja DOM:

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

Python dostarcza pełny, W3C-standardowego wdrożenia XML DOM (xml.dom) i minimalną, xml.dom.minidom. Ten ostatni jest prostszy i mniejszy niż pełne wdrożenie. Jednak z perspektywy "analizowania" ma ona wszystkie zalety i wady standardowego DOM - tj. Ładuje wszystko w pamięci.

Biorąc pod uwagę podstawowy plik 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> 

Możliwym parser Python korzystając minidom jest:

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 

Zauważ, że xml.parsers.expat to interfejs Pythona do Expat nie sprawdzający poprawności analizator składni XML (docs.python.org/2/library/pyexpat.html).

W xml.dom materiały pakietowe również klasa wyjątek DOMException, ale to nie jest supperted w minidom!

ElementTree XML API:

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

ElementTree jest znacznie łatwiejszy w użyciu i wymaga mniej pamięci niż XML DOM. Ponadto dostępne jest implementacja C (xml.etree.cElementTree).

Możliwym parser Python stosując ElementTree jest:

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

Dzięki! Bardzo pomocne. Nie jestem wystarczająco pewny, aby go edytować, ale myślę, że (a) reszta nie jest pomocna, ponieważ nie ma wreszcie: http://stackoverflow.com/questions/855759/python-try-else; (b) zwykłe przebicie zachowałoby więcej niż przebicie e: http://stackoverflow.com/questions/11420464/python-catch-exceptions-inside-a-class –

+0

Odnośnie punktu (a), tak. Nie ma ostatecznego stwierdzenia po prostu dlatego, że w moim przykładzie nie było potrzeby. Nie pamiętam, dlaczego to zrobiłem. Jednak nawet jeśli jest to bezużyteczne w tym przypadku, posiadanie instrukcji else nie jest syntaktycznie błędne. –

+0

Jeśli chodzi o punkt (b), może tak być. Myślę jednak (w moim przykładzie), że jest to trochę poza zakresem. Rzeczywiście, kod miał być tylko prostym przykładem parsowania XML ... –

Powiązane problemy