PHP 5 und XML
XML einfach

DeveloperIT-ProjekteSoftware

Ist für Sie XML auch eine abstrakte Thematik, der Sie wenig abgewinnen können? Internet Professionell zeigt, wie Sie mit PHP 5 eine sehr praxisnahe XML-Aufgabe einfach lösen können.

Open-Office-Dokument ins Web

PHP 5 und XML

Die Aufgabenstellung für das PHP-Skript ist, die von der Internet Professionell monatlich aktualisierte Liste der Webspace-Provider ins Web zu bringen. Die Providerübersicht liegt als Spreadsheet vor, das mit Open Office angelegt wurde. Dieses Dateiformat besteht aus einer Reihe von XML-Dateien, die als ZIP-Archiv gepackt sind, allerdings mit der Endung SCX. Das Skript muss also diese Liste entpacken, die gewünschten Daten daraus via Simple XML extrahieren und in einer gefälligen HTML-Liste darstellen.


Von SCX nach XML

PHP 5 und XML

Zuerst stellt sich die Frage, wie man per PHP aus diesem Archiv die Datei content.xml herausbekommt, in der der Tabelleninhalt steht. Die anderen Dateien des Archivs enthalten beispielsweise die Formatierung oder Programmeinstellungen, sind also für unseren Zweck nicht notwendig. PHP kann bekanntlich nicht direkt mit ZIP-Dateien umgehen. Dafür gibt es zwar mit der so genannten ZZIPLib eine Erweiterung, diese ist aber bei keiner Standardinstallation enthalten und darum bei kaum einem Webspace-Provider aktiviert.

Eine andere Möglichkeit wäre der Einsatz des externen Tools UNZIP ? nur ist das vielleicht gerade bei Ihrem Provider nicht vorhanden oder er hat es für den Zugriff durch PHP-Skripts gesperrt.

Mit PCLZIP von Vincent Blavet existiert eine freie Bibliothek für PHP, die das Packen und Entpacken von ZIP-Archiven ermöglicht. Damit dieses ZIP-Paket korrekt funktioniert, muss die zlib-Bibliothek auf dem Server installiert sein. Die dürfte aber auf jedem Webserver verfügbar sein, bildet sie doch eine wichtige Grundlage für eine ganze Reihe von Programmen und Funktionen. So sorgt sie beispielsweise dafür, dass bei entsprechender Einstellung des Webservers HTML-Dateien gepackt zum Browser übertragen werden und so die Ladezeiten kürzer werden.

Für unseren Anwendungsfall ist sehr praktisch an der Bibliothek PCLZIP, dass sie das Entpacken einer komprimierten Datei in einen String erlaubt ? denn den kann man Simple XML direkt als Eingabe vorsetzen und spart sich so den Umweg der Speicherung in eine Datei. Entpacken Sie das Archiv von PCLZIP am besten ? wie in unserem Transformationsskript vorgesehen ? ins Unterverzeichnis pclzip-2-1, dann müssen Sie den dort eingetragenen Pfad nicht ändern.

Der Codeteil, der sich um Entpacken und Einlesen der Datei content.xml kümmert, sieht prinzipiell so aus (die Fehlerbehandlung ist hier nicht dargestellt).

$archive = new PclZip('provider.scx');
$list = $archive->extract(PCLZIP_OPT_BY_NAME, "content.xml", PCLZIP_OPT_EXTRACT_AS_STRING);
$xml = simplexml_load_string($list[0] ['content']);

Mit drei Zeilen PHP-Code ist das XML-Objekt also bereits bestückt und einsatzbereit!


Struktur der XML-Datei

PHP 5 und XML

Sieht man sich die Datei content.xml an, stellt man nach kurzer Orientierungsphase fest, dass die Grundstruktur einigermaßen klar ist: Im mit dem Tag gekennzeichneten Hauptteil sind nacheinander alle enthaltenen Tabellen aufgeführt. Von ihnen wird im Skript allerdings nur die erste benötigt. Die einzelnen Zeilen sind in aufeinander folgenden Abschnitten der folgenden Form angeordnet:


table:style-name="ro1">

Die Zellen einer Zeile sind hierin jeweils mit einem Tag vertreten, das zum Beispiel so aussieht:


Für die gestellte Aufgabe eignet sich nun leider eine der Hauptattraktionen von Simple XML gar nicht gut: die Umwandlung der XML-Struktur in eine Objekthierarchie. Was sich sonst sehr schön dazu nutzen lässt, um für sich selbst sprechende Ausdrücke wie $xml->genre->titel->autor in den Programmen zu verwenden, bringt Sie bei der hier notwendigen Massenabfertigung von Spalten und Zeilen nicht weiter.

Dafür verfügt Simple XML aber über die Methode Xpath, die generell in der XML-Welt Verbreitung findet. Xpath ist in etwa das für XML, was SQL-Abfragen für Datenbanken darstellen: Mit ihrer Hilfe gibt man ein Suchmuster vor, und bekommt alle dazu passenden XML-Daten. Das sieht dann so aus:

foreach($xml->xpath( ) as $row)
{?}

Dieser Ausdruck bewirkt eine Schleife über alle zum Suchmuster passenden Einträge in der XML-Datei, die in die Variable $xml eingelesen wurde. Dabei nimmt die Variable $row bei jedem Durchlauf den Wert des jeweiligen passenden Knotens ein, inklusive seiner Unterknoten.

Das Suchmuster ist im vorliegenden Fall einfach der Pfad der XML-Tags von der Wurzel bis zu den einzelnen Zeilen. Er lautet:

/office:document-content/
office:body/table:table/
table:table-row

Der Schrägstrich funktioniert dabei in etwa so wie die Pfadangaben in einem Dateisystem: Zu Beginn verwendet, bewirkt er, dass der gesuchte Pfad an der Wurzel des Dokuments beginnen muss. Sollte also zufällig in einem Unterknoten dieselbe Hierarchie von Tags auftauchen, wird diese von Simple XML trotzdem übergangen.

In der Schleife über alle Zeilen ist dann wiederum ein foreach-Konstrukt eingebaut, das innerhalb einer Zeile alle Zellen behandelt. Auch das macht von Xpath Gebrauch.


Einfache Formatierung

PHP 5 und XML

Eine einfache Logik in der äußeren Schleife sorgt dafür, dass das Ergebnis ansprechend formatiert wird: Ein Zähler merkt sich dabei die aktuelle Zeilennummer und weist den Zeilen abwechselnd CSS-Klassen zu, um sie in unterschiedlicher Farbe auszeichnen zu können. Der allerersten Zeile wird sogar noch ein eigener Stil spendiert, um die Spaltenüberschriften hervorheben zu können. Die Ausgabe erfolgt dabei in einer HTML-Tabelle, die bis auf die CSS-Klassen keine Besonderheiten aufweist.

Weil die Daten im XML-Dokument im Codeformat UTF-8 vorliegen, wird zur korrekten Darstellung der deutschen Umlaute und anderer Sonderzeichen der Zelleninhalt noch mit der Funktion utf8_decode() wieder umgewandelt. Die Ausgangstabelle enthält viele Spalten, die man vielleicht gar nicht alle angezeigt bekommen möchte. Dazu ist im Skript ein einfaches Verfahren vorgesehen. Optional kann der Parameter columns an das Skript übergeben werden. Er muss dann durch Doppelpunkte getrennt die Nummern der Spalten enthalten, die man sehen soll. Um beispielsweise nur die Spalten 1,2 und 4 zu erhalten, rufen Sie das Skript so auf:

provider.php?columns=1:2:4

Intern erfolgt die Beachtung dieser Vorgabe dann ganz einfach: Analog zum Zeilenzähler gibt es einen Spaltenzähler, der in jeder Zeile von neuem hochgezählt wird. Vor jeder Ausgabe einer Spalte wird nachgesehen, ob die aktuelle Spaltennummer im Vergleichsstring enthalten ist. Nur dann erfolgt die Ausgabe. Primitiv, aber es funktioniert. Macht man keine Vorgabe, dann kommt eine Standardauswahl der wichtigsten Spalten zum Einsatz.


Das Open Office-XML-Format

PHP 5 und XML

So einfach sich mit PHP 5 und Simple XML arbeiten lässt, ein Nachteil tritt gerade bei der Verarbeitung des Open-Office-Dokuments auf. Denn das Format verwendet so genannte Namespaces. Dies äußert sich in Tags, die über ein vorangestelltes Schlüsselwort verfügen, das durch einen Doppelpunkt abgesetzt ist, wie man beim Xpath-Suchausdruck sehen kann.

Nur verstößt das gegen die Konvention von PHP, dass Variablennamen keinen Doppelpunkt enthalten dürfen. Die Verwendung der praktischen Umwandlung von XML-Hierarchien in ihr Objekt-Gegenstück würde im Beispiel aus diesem Grund scheitern, ist aber glücklicherweise auch nicht notwendig.

Das Problem ist den Entwicklern von PHP 5 bekannt und wird sicher in einer der nächsten Versionen von Simple XML gelöst werden.