25.11 xmlreader 

Version: 1.0 | Lizenz: PHP-Lizenz 3.0 |
Der xmlreader ist ein kleiner, schneller Pull-Parser, um XML-Dateien einzulesen. Zwar ist der Funktionsumfang sicher nicht so groß wie das, was andere Lösungen bieten, aber er bietet meiner Meinung nach alles das, was man benötigt.
Die Erweiterung ist für PPH 5 geschrieben und arbeitet objektorientiert.
Nachdem Sie ein neues Objekt der Klasse xmlreader abgeleitet haben, können Sie diesem entweder direkt XML-Daten übergeben, oder Sie übergeben dem Objekt den Namen einer Datei, die dann eingelesen und verarbeitet wird.
Um direkt XML-Code zu übergeben, nutzen Sie die Methode XML(), der Sie die Daten als Parameter übergeben. Möchten Sie Daten aus einer Datei einlesen, rufen Sie die Methode open() auf, welche den Dateinamen als Parameter übergeben bekommt.
Das eigentliche Auslesen der Daten übernimmt die Methode read(), die jeweils ein Element ausliest und in dem xmlreader-Objekt bereitstellt. Das heißt, die Methode gibt die Daten nicht im eigentlichen Sinne zurück, sondern legt sie im Objekt ab, wo sie dann mit anderen Methoden ausgelesen werden können.
Folgendes Beispiel stellt das Verfahren dar:
<?php // XML-Code, der verarbeitet werden soll $xmlcode = ' <kontakte> <!-- Hier kommt Person 1 --> <person> <name geschl="m">Arthur Dent</name> <telefon>040/1231</telefon> </person> <person> <name geschl="m">Ford Prefect</name> <mobil provider="d3">0191/12756</mobil> </person> </kontakte>'; // Neues Objekt ableiten und XML-Code uebergeben $reader = new Xmlreader(); $reader->XML($xmlcode); // Alle Elemente abarbeiten while (true == $reader->read()) { // Handelt es sich nicht um ein End-Element? if (XMLREADER_END_ELEMENT != $reader->nodeType) { // Element ausgeben echo "Element: $reader->name<br />"; echo "Wert: $reader->value<br />"; echo "Tiefe: $reader->depth<br />"; // Handelt es sich um ein oeffnendes Tag und // hat das Element Attribute? if (XMLREADER_ELEMENT == $reader->nodeType && true == $reader->hasAttributes) { // Erstes Attribut auslesen $attr = $reader->moveToFirstAttribute(); while (true == $attr) { // Attribut ausgeben echo " Attribute Name: $reader->name<br>"; echo " Attribute Wert: $reader->value<br>"; // Pointer auf naechstes Attribut $attr = $reader->moveToNextAttribute(); } } echo "<br>"; } } ?>
Listing 25.14 Lesen von Daten mit dem xmlreader
Wie Sie in Listing 25.14 sehen können, ist die Verarbeitung der XML-Daten sehr einfach. Nachdem die XML-Daten an das Objekt übergeben worden sind, können Sie jeweils das nächste Element mit der Methode read() lesen. Man spricht dabei auch davon, dass der interne Cursor, eine Art Zeiger, auf das nächste Element gesetzt wird. Als Elemente werden hierbei öffnende und schließende Tags sowie die Daten zwischen dem öffnenden und schließenden Tag betrachtet. Die Methode liefert das Element und die Daten nicht zurück, sondern stellt diese im Objekt bereit. Die Eigenschaft nodeType teilt Ihnen mit, was für eine Art von Knoten das gefundene Element darstellt. Diese Information können Sie mit verschiedenen vordefinierten Konstanten vergleichen, um herauszufinden, um was es sich handelt. Die wichtigsten Konstanten finden Sie in Tabelle 25.1.
Sobald der Cursor auf ein Element gesetzt worden ist, können Sie verschiedene Eigenschaften auslesen, um das Element verarbeiten zu können. Wie schon erwähnt, ist der Typ des gefundenen Elements in nodeType abgelegt. In der Eigenschaft name ist der Name des Elements abgelegt. Handelt es sich um ein Tag, ist hier der Name zu finden. Bei Kommentaren, Text-Elementen und Ähnlichem wird hier ein »Dummy-Name« wie #text oder #comment verwendet.
Die Eigenschaft value speichert den Wert, der in diesem Element abgelegt ist, und in depth ist die Verschachtelungstiefe abgelegt. Das heißt, das Root-Element befindet sich in der Ebene 0, das nachfolgende (im obigen Beispiel person) in der Ebene 1, und Elemente, die darin verschachtelt sind, liegen auf der zweiten Ebene. Möchten Sie herausfinden, ob ein Element einen Wert enthält oder ob es leer ist, können Sie die Eigenschaften hasValue bzw. isEmptyElement auswerten, die Ihnen mithilfe eines booleschen Wertes mitteilen, ob ein Wert vorhanden ist oder nicht.
Wenn ein Element über Attribute verfügt, speichert das System die Anzahl in der Eigenschaft attributeCount und die Eigenschaft hasAttributes enthält den Wert true.
Ein Element, das verarbeitet wird, kann, wenn es ein öffnendes Tag ist, über Attribute verfügen. Daher wird in der zweiten if-Abfrage erst überprüft, ob der Typ des Knotens der Konstante XMLREADER_ELEMENT entspricht. Danach wird erst getestet, ob die Eigenschaft hasAttributes dem Wert true entspricht. Somit kann vermieden werden, dass jedes Element darauf geprüft wird, ob es Attribute enthält.
Um den Cursor auf dem ersten Attribut zu platzieren, wird die Methode moveToFirstAttribute() aufgerufen. Auch hierbei können die Informationen wieder mithilfe von Eigenschaften ausgelesen werden. Nachdem das Attribut verarbeitet worden ist, wird der Cursor mithilfe von moveToNextAttribute() auf das nächste Attribut gesetzt.
Die Ausgabe aus Listing 25.14 beginnt mit den folgenden Elementen:
Element: kontakte Wert: Tiefe: 0 Element: #text Wert: Tiefe: 1 Element: #comment Wert: Hier kommt Person 1 Tiefe: 1 Element: #text Wert: Tiefe: 1 Element: person Wert: Tiefe: 1 Element: #text Wert: Tiefe: 2 Element: name Wert: Tiefe: 2 Attribute Name: geschl Attribute Wert: m Element: #text Wert: Arthur Dent" Tiefe: 3 // gekuerzte Ausgabe
Sie sehen, dass nach jedem Element Content ausgegeben wird. Das ist selbst dann der Fall, wenn ganz offensichtlich kein Text vorhanden ist. In dem Fall handelt es sich um Whitespaces wie Zeilenumbrüche oder Leerzeichen. Um solche Ausgaben zu unterdrücken, können Sie den nodeType prüfen.
Ein ganz besonderes Feature des Pakets ist, dass sowohl DTDs als auch Relax NG-Schemata genutzt werden können, um die Validität einer XML-Datei zu prüfen.
Eine Validierung des XML-Codes mithilfe einer DTD könnte so aussehen, dass Sie, nachdem Sie den XML-Code eingelesen haben, diese beiden Zeilen ergänzen:
$reader->setParserProperty(XMLREADER_LOADDTD, true); $reader->setParserProperty(XMLREADER_VALIDATE, true);
Damit wird die DOCTYPE-Processing-Instruction gelesen und der dort enthaltene Verweis auf die DTD ausgewertet. Die DTD wird geladen, und mit der zweiten Zeile wird die Validierung eingeschaltet.
Möchten Sie gegen ein RelaxNG-Schema validieren, müssen Sie das Schema zuerst mit der Methode setRelaxNGSchema() festlegen, der Sie den Dateinamen und den Pfad des Schemas übergeben. Um zu prüfen, ob der XML-Code den Vorgaben des Schemas entspricht, rufen Sie dann die Methode isValid() auf, die einen booleschen Wert zurückgibt.