In diesem Artikel wird erklärt, wie mit der PHP-Erweiterung "SimpleXML" auf XML-Dokumente mit Namensräumen zugegriffen werden kann. Er ist keine Einführung in SimpleXML, sondern behandelt ein spezifisches Problem.
Gut gelungene Tutorials zu SimpleXML sind z.B. unter den folgenden Links zu finden:
Weitere Links zum Thema befinden sich am Ende des Artikels.
Auf ein Dokument ohne Namensräume kann mit SimpleXML intuitiv über die PHP Objektsyntax zugegriffen werden. Als Beispiel wird ein vereinfachter Ausschnitt aus einer vom ITScope-Webservice gelieferten XML-Datei benutzt.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<catalogueResponse>
<productResponse>
<productResults>3</productResults>
<product entryDate="2009-01-31T00:00:00+01:00">
<uid>PRO-10654653</uid>
</product>
</productResponse>
</catalogueResponse>
Um das Element "uid" auszulesen, genügt eine einzige Zeile:
$itScopeId = (string) $xmlObject -> productResponse -> product -> uid;
Dieser einfache Zugriff ist möglich, weil alle Elemente des XML-Dokuments im Null-Namensraum stehen.
Die Behandlung von XML-Dokumenten ohne Namensräume ist mit SimpleXML also sehr einfach; etwas anders sieht es aus, wenn ein oder mehrere XML-Elemente Namensräume benutzen.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<its:catalogueResponse xmlns:its="http://www.itscope.de/IWS/2006-04-20" xmlns:its3="http://www.itscope.de/IWS3/2008-05-01">
<its:productResponse>
<its:product entryDate="2009-01-31T00:00:00+01:00">
<its:uid>PRO-10654653</its:uid>
<its3:irank>55137</its3:irank>
</its:product>
</its:productResponse>
</its:catalogueResponse>
Dieses Beispiel verfügt über zwei Namensräume, die über die Attribute "xmlns" im Element "catalogueResponse" definiert und durch URLs ("http://www.itscope.de/IWS/2006-04-20" und "http://www.itscope.de/IWS3/2008-05-01") dargestellt werden.
Die zwei Namensräume werden an die Präfixe "its" und "its3" gebunden, die damit wie Aliase eingesetzt werden können; statt "<its:uid>" könnte man genauso gut schreiben "<uid xmlns='http://www.itscope.de/IWS/2006-04-20'>", allerdings würde die Lesbarkeit des XML-Dokuments sehr darunter leiden.
Obwohl sie Komplexität hinzufügen, werden Namensräume vor allem aus einem Grund eingesetzt: sie erlauben es, mehrere XML-Sprachen miteinander zu vermischen. In ein XHTML-Dokument kann so z.B. ein MathML-Dokument eingebettet werden, ohne dass die MathML-Struktur in der XHTML-DTD definiert sein muss. Damit ist auch eine gewisse Erweiterbarkeit gegeben.
Doch zurück zu SimpleXML. Elemente, die einem Namensraum zugeordnet sind, sind nur über diesen erreichbar. Der Aufruf
$itScopeId = (string) $xmlObject -> productResponse -> product -> uid;
funktioniert in Beispiel 2 deswegen nicht, weil mit dieser Syntax das Element "productResponse" im Null-Namensraum gesucht wird. Tatsächlich steht es aber im Namenraum "its". Somit stellt sich die Frage, wie wir auf die Elemente zugreifen können, die einem Namensraum zugeordnet sind.
SimpleXML-Elemente stellen zwei Methoden bereit, mit denen die Behandlung von Namensräumen sehr einfach wird, nämlich "attributes" und "children". Da wir über den Zugriff auf Elemente reden, beschränken wir uns hier auf die "children"-Methode. Außerdem verwenden wir die Methode "getNamespaces", um auf bequeme Weise alle im XML-Dokument benutzten Namensräume zu erhalten.
Zuerst lesen wir über die Methode "getNamespaces" alle Namensräume, die für dieses XML-Dokument definiert sind, in die Variable $namespaces ein.
$xmlObject = simplexml_load_string($xmlString);
$namespaces = $xmlObject -> getNamespaces(true);
"getNamespaces" gibt ein assoziatives Array zurück, das in unserem Fall folgendermaßen aussieht:
Array
(
[its] => http://www.itscope.de/IWS/2006-04-20
[its3] => http://www.itscope.de/IWS3/2008-05-01
)
Jetzt können wir mit der Methode "children" alle Knoten des XML-Dokuments laden, die unter dem als Parameter übergebenen Namensraum liegen. Auf das Ergebnis kann mit der gleichen intuitiven Syntax wie in Beispiel 1 (XML ohne Namensräume) zugegriffen werden.
$itScopeId = (string) $xmlObject -> children($namespaces['its']) -> productResponse -> product -> uid;
Da alle Elemente, die wir für die Suche nach "uid" benötigen, im gleichen Namensraum liegen und dieser direkt unter der Dokumentwurzel beginnt, reicht es aus, die Methode "children" direkt auf dem obersten XML-Element auszuführen.
Um das Element "irank" aus dem Namensraum "its3" auszulesen, müssen wir einen weiteren Zwischenschritt einbauen, da dieses unter den Elementen "productResponse" und "product" liegt, die im Namenraum "its" liegen:
$iRank = (string) $xmlObject -> children($namespaces['its']) -> productResponse -> product -> children($namespaces['its3']) -> irank;
Hier ist der komplette Sourcecode für ein lauffähiges PHP-Script:
<?php
$xmlString = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<its:catalogueResponse xmlns:its="http://www.itscope.de/IWS/2006-04-20" xmlns:its3="http://www.itscope.de/IWS3/2008-05-01">
<its:productResponse>
<its:product entryDate="2009-01-31T00:00:00+01:00">
<its:uid>PRO-10654653</its:uid>
<its3:irank>55137</its3:irank>
</its:product>
</its:productResponse>
</its:catalogueResponse>';
$xmlObject = simplexml_load_string($xmlString);
$namespaces = $xmlObject -> getNamespaces(true);
$itScopeId = (string) $xmlObject -> children($namespaces['its']) -> productResponse -> product -> uid;
$iRank = (string) $xmlObject -> children($namespaces['its']) -> productResponse -> product -> children($namespaces['its3']) -> irank;
?>
Danke vielmal für diese geniale Tutorial! Nun habe auch ich es kapiert! ;)
Posted by pn91, 26/07/2010 3:13pm (vor 2 Jahre)
Jetzt habe ich es auch endlich verstanden. :-) Vielen Dank!
Posted by Jan, 04/07/2010 6:56pm (vor 2 Jahre)
Sehr hilfreich. Vielen Dank!
Posted by Plamen Rusinov, 19/04/2010 1:56am (vor 2 Jahre)
RSS Feed für die Kommentare auf dieser Seite | RSS feed für alle Kommentare