Native Parser-Schnittstellen
(Auszug aus "Python & XML" von Christopher A. Jones & Fred L. Drake, Jr.)
Nun, da wir gesehen haben, wie SAX verwendet werden kann und wie sehr sich der Code zum Aufsetzen des Parsers und des ContentHandler doch ähnelt, werden Sie sich vielleicht fragen, wieviel von dieser Leichtigkeit auf SAX zurückzuführen ist und wieviel auf Hilfsfunktionen der Python-Bibliotheken? Wir werden zwar nicht tief in die nativen Schnittstellen der individuellen Parser eintauchen, aber dies ist eine gute Frage, die zu einigen interessanten Beobachtungen führen kann.
Der wichtigste Vorteil bei der Benutzung von SAX ist der, daß die Callback-Methoden die gleichen Namen und die gleiche Bedeutung haben, unabhängig vom tatsächlichen Parser, den Sie benutzen. Daraus ergeben sich mindestens zwei nette Eigenschaften: Ein Parser-Wechsel betrifft Ihre Anwendung nicht, und Ihr Code ist leichter zu warten, weil jemand, der ihn noch nicht kennt, wahrscheinlich eher die SAX-Schnittstelle als irgendeine Parser-spezifische Schnittstelle kennt.
Wie unterscheiden sich also die nativen Schnittstellen der individuellen Parser von SAX, und warum würden wir sie statt dessen benutzen wollen? Sehen wir uns kurz den PyExpat-Parser an, um einen Eindruck von den Unterschieden zu bekommen.
Direkte Verwendung von PyExpat
Natürlich muß man PyExpat erst einmal installiert haben, um es benutzen zu können. Es ist als Teil des Python-Installers für Windows verfügbar und wird unter Unix automatisch gebaut, wenn Sie die Expat-Bibliothek installiert haben. Wenn Sie PyExpat nicht als Teil von Python installiert haben, ist es als Teil des PyXML-Pakets installiert.
PyExpat sitzt im Modul xml.parsers.expat. Wenn wir unser letztes Beispiel so modifizieren wollen, daß es PyExpat direkt benutzt, haben wir nicht viel zu tun, aber ein paar Änderungen gibt es doch. Da die PyExpat-Handler-Methoden sehr denen des SAX-Handlers entsprechen, jedenfalls für den einfachen Gebrauch, den wir hier vorstellen, können wir die gleiche Handler-Klasse benutzen, die wir schon geschrieben haben. Die import-Anweisungen müssen nicht groß verändert werden:
#!/usr/bin/env python
import sys
from xml.parsers import expat
from handlers import PyXMLConversionHandler
Ist der Parser einmal importiert, kann er erzeugt und benutzt werden:
parser = expat.ParserCreate( )
Täten wir dies bei der interaktiven Eingabeaufforderung, könnten wir das Parser-Objekt anbohren, um zu sehen, welche Attribute es hat:
>>> from xml.parsers import expat
>>> parser = expat.ParserCreate( )
>>> dir(parser)
['CharacterDataHandler', 'CommentHandler', 'DefaultHandler', 'DefaultHandlerExpa
nd', 'EndCdataSectionHandler', 'EndElementHandler', 'EndNamespaceDeclHandler', '
ErrorByteIndex', 'ErrorCode', 'ErrorColumnNumber', 'ErrorLineNumber', 'ExternalE
ntityParserCreate', 'ExternalEntityRefHandler', 'GetBase', 'NotStandaloneHandler
', 'NotationDeclHandler', 'Parse', 'ParseFile', 'ProcessingInstructionHandler',
'SetBase', 'StartCdataSectionHandler', 'StartElementHandler', 'StartNamespaceDec
lHandler', 'UnparsedEntityDeclHandler', 'ordered_attributes', 'returns_unicode',
'specified_attributes']
Das sieht gewiß nicht wie ein SAX-Parser aus!
Es gibt weder eine setContentHandler-Methode noch irgend etwas, was ihren Platz einnimmt. Um unseren Content-Handler zu registrieren, müssen wir verschiedenste Attribute in den Methoden einer Content-Handler-Instanz setzen:
dh = PyXMLConversionHandler(sys.stdout)
parser.StartElementHandler = dh.startElement
parser.EndElementHandler = dh.endElement
parser.CharacterDataHandler = dh.characters
Das ist zwar nicht schwer, aber gewiß aufwendiger als die Methode setContentHandler in SAX. Und der Code muß tatsächlich geändert werden, da wir mehrere Methoden vom Handler-Objekt benutzen müssen.
Nachdem wir die Handler-Methoden initialisiert haben, an deren Verwendung wir interessiert sind, können wir mit dem Parsen beginnen. Wieder ist dies ein wenig anders als bei der SAX-Version:
parser.Parse(sys.stdin.read( ), 1)
Wir wissen, was sys.stdin.read( ) tut, aber die 1, die beim zweiten Parameter benutzt wird, sieht verdächtig nach einer magischen Zahl in unserem Quellcode aus. Tatsächlich ist es ein Boolescher Wert, der angibt, daß der String, der an die Parse-Methode übergeben wird, der letzte Happen der Eingabe ist; Parse kann mehrfach mit kleineren Eingabeportionen und einem auf 0 gesetzten Flag aufgerufen werden und kann schließlich mit einem Wert von 1 beim letzten Datenhäppchen aufgerufen werden. Das kann nützlich sein, wenn Daten asynchron über eine Netzwerkverbindung gelesen werden.
Zum Parsen von XML aus einem Dateiobjekt ist auch die folgende Methode verfügbar:
parser.ParseFile(sys.stdin)
Das komplette Skript, das den Handler mit PyExpat benutzt, wird im folgenden Beispiel gezeigt.
Beispiel: genhtml2.py mit PyExpat
"""
genhtml2.py - erzeugt HTML aus pyxml.xml
"""
import sys
from xml.parsers import expat
from handlers import PyXMLConversionHandler
dh = PyXMLConversionHandler(sys.stdout)
parser = expat.ParserCreate( )
parser.StartElementHandler = dh.startElement
parser.EndElementHandler = dh.endElement
parser.CharacterDataHandler = dh.characters
parser.ParseFile(sys.stdin)
Die Ausgabe geht auf den Standardausgabestrom. Wenn sie in Ihrem Browser geöffnet wird, zeigt sie Ihnen alle Klassen des PyXML-Pakets und deren Methoden an, genau wie es die reine SAX-Version dieses Beispiels tat.
<< zurück | vor >> |
Tipp der data2type-Redaktion: Zum Thema Python & XML bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an: |
Copyright © 2002 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "Python & XML" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.
O’Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de