
XML mit PHP zu verarbeiten ist durch die Integration von James Clarks XML-Parser Expat schon länger recht einfach. Aber nicht jeder will seine XML-Daten mit XSLT in andere Formate, meist HTML, wandeln. XML Transformer, ein Bestandteil des PEAR (PHP Extension and Application Repository, siehe Online-Ressourcen), verfolgt die Lösung zweier Aufgaben, die nur auf den ersten Blick unkorreliert erscheinen. Zum einen suchen viele nach einem eleganten Weg, um PHP-Objekte ins Web zu bringen. Zum anderen ist die Transformation von XML-Daten aus einem Format in ein anderes bei der Entwicklung von Webapplikationen omnipräsent.
Vom Arbeitsprinzip her ist die Extensible Stylesheet Language Transformations (XSLT) des W3C mit awk verwandt: Bedingungen (Template Match) oder Funktionen (Template Name) werden nacheinander auf die Eingabe angewendet. Diese hat bei awk Zeilen, bei XSLT (siehe dazu das iX-Tutorial von 2001) liegt sie als Baumstruktur vor. Wie awk kann XSLT nicht auf seine Ausgabe zugreifen.
Stylesheets, wie in XSLT geschriebene Programme aus historischen Gründen heißen, sind ihrerseits XML-Dokumente. Daher ist XSLT geschwätzig, sogar einfache Sprachkonstrukte erfordern viel Schreibarbeit. Listing 1 zeigt oben den nötigen Code, um ein if-then-else in XSLT zu realisieren, unten das hierzu äquivalente PHP-Schnipsel.
XSLT ist eine funktionale Transformationssprache und bringt daher die Nachteile funktionaler Programmiersprachen mit sich, beispielsweise den Umweg über Rekursion für das Ausdrücken von Schleifen oder Variablen, die eher konstant als variabel sind. Außerdem kann man die Vorteile der funktionalen Programmierung, etwa das Rechnen mit Funktionen als Datentypen oder die Programmierung mit Closures, nicht nutzen. Die bietet XSLT nicht.
Ein weiterer Nachteil von XSLT liegt in der Domainbeschränkung: Während XSLT alles über die Extensible Markup Language weiß und diesbezügliche Funktionen anbietet, weiß es relativ wenig von Dingen, die nichts mit XML zu tun haben. Ohne die Einbeziehung von in anderen Programmiersprachen, beispielsweise Java, geschriebenen Programmen über Callbacks können XSLT-Stylesheets nicht mit der Welt jenseits von XML interagieren. Daten aus anderen Quellen zu beziehen, etwa aus einer Datenbank, oder nicht textbasierte Ausgabeformaten (Grafiken oder PDF) zu erzeugen, ist ohne Fremdhilfe nicht machbar.
XML Transformer (gegenwärtig in der Version 0.8.2.) hingegen erlaubt die prozedurale Definition von Transformationen, wobei sich sämtliche Fähigkeiten von PHP wie der Zugriff auf Datenbanken oder die Erzeugung von Grafiken, nutzen lassen. Das Ergebnis eines Zwischenschritts kann im Gegensatz zu XSLT als Eingabe für den nächsten dienen.
Im Wesentlichen besteht die Kodierung mit dem XML Transformer aus der Nutzung vorhandener Namespace Handler oder dem Schreiben eigener. In Listing 2 kommt der im Paket enthaltene Image Namespace Handler zum Tragen. Dieser bietet unter anderem ein intelligentes <img />-Element, das die width- und height-Attribute automatisch auf Basis der per getimagesize erkannten Bildinformationen setzt.
Listing 3 lädt zunächst die XML_Transformer- und XML_Transformer_Namespace_Image-Klassen. Danach erzeugt es ein Objekt der Klasse XML_Transformer, und der img-Namensraum wird im Konstruktor an die Klasse XML_Transformer_Namespace_Image gebunden. Die eigentliche Transformation leistet die Methode transform() (siehe Listing 2), die als einzigen Parameter die XML-Eingabe als String übergeben erhält.
Für das Setzen von Parametern und die Definition von Transformationen hält die XML_Transformer-Klasse set-Methoden bereit. So erzeugt Listing 3 (das keine Ausgabe generiert) beispielsweise zunächst ein Objekt der XML_Transformer-Klasse, aktiviert im Anschluss den Debugmodus und lädt die Transformationen des Namensraum-Handler für das Bild.
Parameter und Transformationen lassen sich auch zum Zeitpunkt der Objekterzeugung über den Konstruktor der XML_Transformer-Klasse setzen (siehe Listing 2).
Neben der direkten Verwendung der XML_Transformer-Klasse und der Transformation der XML-Eingabe über deren transform()-Methode bietet das Paket so genannte Treiberklassen an, die das Standardverhalten erweitern. Listing 4 zeigt die Verwendung der Treiberklasse XML_Transformer_Driver_OutputBuffer. Sie benutzt den Output-Buffering-Mechanismus von PHP, um die gesamte Ausgabe des Scripts, in dem sie verwendet wird, zu puffern und anschließend als XML-Eingabedokument zu benutzen.
Eine weitere Treiberklasse ist XML_Transformer_Driver_Cache, die das Ergebnis der Transformation in einem Cache speichert. Zukünftige Transformationen für identische XML-Eingabe und die verwendeten Transformationen lassen sich kostensparend aus ihm bedienen. Mit der Klasse XML_Transformer_Namespace_Image hat Listing 2 schon einen der zum Paket gehörenden Namensraum-Handler genutzt. Der gleichnamige Kasten zeigt einen Überblick über alle im Paket enthaltenen.
Im Folgenden soll es um die Programmierung eigener Namespace Handler gehen. Wie die vorangegangenen Listings gezeigt haben, bindet XML Transformer PHP-Funktionen an XML-Elemente, indem eine Klasse an einen Namensraum gebunden wird. Der Pseudo-Namespace &MAIN dient dazu, dies ohne assoziierten Namespace zu tun. Für jedes Element des mit ihr assoziierten Namensraums implementiert die PHP-Klasse, die sich von XML_Transformer_Namespace ableitet, zwei Methoden, die die Transformation beschreiben: start_ELEMENT($attributes) wird für das öffnende Tag des Elements mit den Attributen als Parameter, end_ELEMENT($cdata) dagegen für das schließende Tag des Elements mit den CDATA-Daten als Parameter aufgerufen.
Beide Methoden können, müssen aber nicht, ein XML-Fragment als String zurückgeben, das anstelle des gerade bearbeiteten Elementes in die Ausgabe eingefügt werden soll. Hierbei ist zu beachten, dass die zurückgegebenen Fragmente die Wohlgeformtheit des XML-Dokuments nicht verletzen.
Listing 5 zeigt mit der HelloWorld-Klasse einen Namespace Handler, der mit den Methoden start_helloWorld() und end_helloWorld() eine Transformation für das <helloWorld />-Element zur Verfügung stellt.
Bei der Entwicklung eines Namespace Handlers sollte man stets bedenken, dass der XML Transformer intern mit dem SAX-Parser arbeitet. So sind beispielsweise weder umordnende Transformationen noch die Erzeugung von Inhaltsverzeichnissen in einem Durchgang durchführbar. Sollte man solche Operationen dennoch benötigen, transformiert man die XML-Eingabe in zwei Durchgängen. Durch Setzen des Attributs $secondPassRequired auf true signalisiert der Namespace Handler den Bedarf eines zweiten Durchlaufs.
Zur Unterstützung bei der Entwicklung neuer Namespace Handler bietet der XML Transformer einen Debug-Modus an. Dieser kann, wie in Listing 2 und Listing 3 zu sehen, sowohl über einen Parameter im Konstruktor der XML_Transformer-Klasse als auch über die Methode setDebug(true) aktiviert werden.
Bei Verwendung der Standardeinstellungen werden Debug-Nachrichten an das Fehlerprotokoll des Webservers gesendet. Eine Bildschirmausgabe, die allerdings bei Verwendung der Treiberklasse XML_Transformer_Driver_OutputBuffer nicht verwendet werden kann, ist ebenfalls möglich.
Listing 6 beinhaltet eine Mini-Anwendung. Sie ist datenbankgestützt, wertet mit $cdata das durch den Parameter übergebene $myterm aus und durchsucht eine Datenbank nach Einträgen, deren Kürzel $myterm enthält. Ist das der Fall, füllt die while-Schleife die Variable $dbbuffer mit Kürzel und Bedeutung, auch bei mehreren Treffern. $dbbuffer ist Bestandteil des return, der wiederum eine ganze HTML-Seite ausgibt.
Leicht ist aus diesem Script eine Anwendung gestrickt, die sämtliche Einträge als Menü zeigt und auf Mausklick die Erklärung für den gewünschten Begriff liefert. XML Transformer lässt sich jedoch außerdem und vor allem nutzen, indem ein solcher Namespace Handler Teile von XML-Dokumenten verarbeitet. Als letzten Namespace Handler enthält Listing 7 eine veränderte Funktion end_Woerterbuch, die das Element Woerterbuch, wie es Listing 8 enthält, in ein <acronym> wandelt. $dbbuffer bekommt den übergebenen Wert von $cdata sowie die dazugehörende Erklärung aus der Datenbank als Attribut title zugewiesen.
In einem wohlgeformten, beliebig umfangreichen XML-Dokument (das kann durchaus HTML sein), wie es Listing 8 andeutet, führt das Einbinden von Woerterbuch.php dazu, dass alle Woerterbuch-Elemente zu Akronymen mit title-Attribut mutieren. Für die wiederum zeigen einige Browser die Bedeutung des Akronyms an, sowie der Mauszeiger über dem Kürzel schwebt.
Listing 6 und 7 machen sich die Namensraumsache einfach, indem sie den Default nutzen:
array( 'overloadedNamespaces' =>array( '&MAIN' =>new Woerterbuch ) )
|
|
Wörterbucheinträge on-the-fly in ein HTML-Element (acronym) gewandelt |
Spätestens wenn sie einen weiteren Namensraum im selben Dokument nutzen wollen, müssen Entwickler darauf achten, dass beim Erzeugen der Driver_OutputBuffer-Klasse das Namespace-Array ein anderes Präfix erhält. Statt &MAIN etwa dummy. Im Dokument ist in einem solchen Fall dieses Präfix dem Element voranzustellen: <dummy:Dummy>oops </dummy:Dummy> (siehe den Screenshot). Was unter anderem bedeutet, dass der Verarbeitung komplexer Dokumente nur etwas Programieraufwand entgegensteht.
Sebastian Bergmann
studiert Informatik in Bonn und ist aktives Mitglied der internationalen PHP-Entwicklergemeinde. Sein Buch Professionelle Softwareentwicklung mit PHP 5 erscheint demnächst im Dpunkt-Verlag.
| iX-TRACT |
|
Dieser Text ist der Zeitschriften-Ausgabe 12/2003 von iX entnommen.
Parallelprogrammierung - die Kunst der Multi-Core-Nutzung
Agile ALM - agile Praktiken im Application Lifecycle Management
Webentwicklung - Applikationen für mobile Clients
HTML5, CSS3, WebGL: Das iX-Sonderheft zum Thema Webdesign fasst die wichtigsten Neuerungen der aktuellen und kommenden Webstandards zusammen.