23 XML
XML und damit verwandte Technologien sind momentan ein großes Thema in der Software-Branche. Zwar ist ein Teil der Aufregung sicherlich übertrieben, aber XML kann in vielen Fällen sehr spannend und hilfreich sein. Vor diesem Hintergrund gibt es auch eine recht große Anzahl von Paketen, die XML verarbeiten können. Die XML-Pakete stellen hierbei »bodenständige« Funktionalitäten zum Generieren oder Verarbeiten von XML zur Verfügung. Pakete zur Nutzung von Web Services finden Sie in der Kategorie »Services«.
Auch in der Kategorie XML musste ich auf ein Paket verzichten, das ich gern mit aufgenommen hätte: XML_sql2xml. Dieses Paket kann aus dem Ergebnis einer PEAR::DB-Datenbankabfrage automatisch ein XML-Dokument erstellen. Leider ist das Paket noch nicht PHP-5-kompatibel. Nutzen Sie noch PHP 4, sollten Sie einen Blick darauf werfen. Es ist gut dokumentiert und kann sehr hilfreich sein.
23.1 XML_Util 

Besprochene Version: 1.1.1 | Lizenz: PHP-Lizenz 2.0 |
Klassendatei(en): XML/Util.php |
XML_Util ist die Basis-Klasse vieler XML-Pakete und stellt Funktionalitäten zur Erstellung von XML-Code zur Verfügung. Diese sind zwar sehr bodenständig, eignen sich aber gut, wenn Sie Software erstellen wollen, die XML generiert. Die Methoden können alle statisch aufgerufen werden.
Eine der einfachsten Methoden ist createTag(), mit der Sie ein Tag mit oder ohne Inhalt erzeugen können. Sie bekommt als ersten Parameter den Namen des Elements übergeben. An zweiter Stelle können Sie – dieser Parameter und die folgenden sind optional – ein assoziatives Array mit Attributen übergeben. Der Schlüssel wird dabei als Name des Attributs verwendet. Möchten Sie, dass das Element einen Inhalt hat, kann dieser danach angegeben werden. Geben Sie diesen nicht an, wird das Tag als leeres Element behandelt und sofort in der Kurzschreibweise <tag /> ausgegeben.
Der String, den Sie an der vierten Stelle übergeben können, legt fest, welcher Wert an das Attribut xmlns übergeben werden soll. Übergeben Sie hier keinen Wert oder null, so wird das Attribut xmlns nicht ausgegeben. Den Namen des Namespaces, der nach xmlns: angegeben wird, extrahiert die Methode aus dem Namen des Tags. Nutzen Sie den Namen 'galileo:monat', wird der Namespace mit xmlns:galileo= deklariert.
Mit einem letzten Parameter können Sie bestimmen, wie Entitäten behandelt werden sollen. Entitäten, die nicht aufgelöst werden können, weil keine dazugehörige DTD vorhanden ist, führen schnell zu einer XML-Datei, die nicht genutzt werden kann. Wenn Sie als letzten Parameter false übergeben, werden die Daten direkt übernommen. Mit der Konstante XML_UTIL_REPLACE_ENTITIES, die auch der Default-Wert ist, wird festgelegt, dass die Entitäten konvertiert werden. Somit wird ein ä in ein &auml; konvertiert. Da das & zu den Entitäten gehört, die ein XML-Prozessor immer verarbeiten können muss, ist die Entität damit »entschärft«. Allerdings wird die Entität dann eventuell auch nicht mehr korrekt dargestellt. Übrigens werden auch Entitäten wie & und " entsprechend in &amp; und &quot; verwandelt.
Die letzte Möglichkeit ist, mit XML_UTIL_CDATA_SECTION festzulegen, dass der Inhalt des Elements in einer CDATA-Section ausgegeben wird.
echo XML_Util::createTag('monat') // Ausgabe: <monat /> echo XML_Util::createTag('monat',null,'märz',null, XML_UTIL_CDATA_SECTION); // Ausgabe: <monat><![CDATA[märz]]></monat> $attr = array ('lang' => 'de'); $name_spc = 'https://www.galileo-press.de'; echo XML_Util::createTag('galileo:monat',$attr,'märz', $name_spc,XML_UTIL_REPLACE_ENTITIES); // Ausgabe: <galileo:monat lang="de" // xmlns:galileo="https://www.galileo-press.de"> // m&auml;rz</galileo:monat>
Die Methode createTag() hat mit der Methode createTagFromArray() noch einen Verwandten. Diese bekommt alle benötigten Daten zur Ausgabe eines Tags in einem Array übergeben, das an erster Stelle in der Parameter-Liste steht. Das Array sollte den folgenden Aufbau haben:
$tag = array( "localPart" => "monat", "namespace" => "galileo", "namespaceUri" => "https://www.galileo-press.de", "attributes" => array( "lang" => "de" ), "content" => "März" );
Der Aufbau ist ein wenig anders, als Sie es vielleicht erwartet hätten. Der Schlüssel localPart verweist auf das eigentliche Tag. namespace beinhaltet den Namen des Namespaces, der in diesem Fall dem Tag aber automatisch vorangestellt wird. Die anderen Elemente verhalten sich wie bei createTag(). In namespaceUri wird die URI des Namespaces definiert, attributes beinhaltet ein assoziatives Array mit den Attributen, und content ist der eigentliche Inhalt des Elements.
Mit einem zweiten Parameter, der optional ist, können Sie steuern, wie Entitäten behandelt werden sollen. Die möglichen Werte und das resultierende Verhalten entsprechen dem von createTag(). Rufen Sie createTagFromArray() mit obigem Array auf, ergibt sich Folgendes:
echo XML_Util::createTagFromArray($tag, false); // Ausgabe: <galileo:monat lang="de" // xmlns:galileo="https://www.galileo-press.de"> // März</galileo:monat>
Diese beiden Befehle bringen Sie aber noch nicht wirklich weiter, da sie es nicht ermöglichen, Tags ineinander zu verschachteln.
Um ein einzelnes Start-Tag auszugeben, ist die Methode createStartElement() definiert, die ihr Gegenstück in createEndElement() findet. create EndElement() bekommt nur den Namen des Tags inklusive eines etwaigen Namensraum-Präfixes übergeben. createStartElement() bekommt als ersten Parameter auch den Namen mit Namensraum-Präfix übergeben. Zusätzlich kann auch hier wieder ein assoziatives Array mit Attributen und die URI eines Namespaces angegeben werden.
Bei der Ausgabe eines neuen Tags kann die Methode isValidName() auch sehr hilfreich sein. Sie bekommt den Namen eines Tags oder Attributs übergeben und liefert ein true zurück, wenn der Name gültig ist. Sollte das nicht der Fall sein, ist ein PEAR_Error-Objekt der Rückgabewert.
Der eigentliche Inhalt eines Elements kann direkt ausgegeben werden. Sollten Sie eine CDATA-Section benötigen, können Sie createCDataSection() nutzen. Die Methode bekommt die auszugebenden Daten als Parameter übergeben und gibt sie, eingeschlossen von <!CDATA[ und ]]> , wieder aus.
Für die Ausgabe des Inhalts sind die Methoden replaceEntities() und reverseEntities() sicher auch noch hilfreich. replaceEntities() bekommt einen Text übergeben, ersetzt Zeichen wie <, > oder &, die in einem Datensatz nicht vorkommen dürfen, durch die entsprechenden Entitäten und liefert den Datensatz zurück. reverseEntities() kehrt diesen Prozess um und liefert den Text, der als Parameter übergeben wurde ohne Entitäten, dafür aber mit Sonderzeichen zurück. Die Zeichen werden dabei im ISO-8859–1-Zeichensatz kodiert.
Um einen Kommentar in eine XML-Datei zu schreiben, ist die Methode createComment() vorgesehen, die einen Text übergeben bekommt und ihn eins zu eins übernimmt und als Kommentar einfügt.
Da eine XML-Datei über eine DOCTYPE-Deklaration verfügen sollte, ist auch dafür eine Methode deklariert. getDocTypeDeclaration() bekommt als ersten Parameter den Namen des Root-Elements übergeben. Danach kann die URI der DTD folgen. Übergeben Sie einen String, geht die Methode davon aus, dass die DTD auf demselben Rechner zu finden ist, und fügt das Schlüsselwort SYSTEM ein. Wollen Sie eine öffentliche DTD referenzieren, übergeben Sie an dieser Stelle ein Array, das aus dem öffentlichen Bezeichner und der URI besteht, unter der die DTD abgelegt ist. Mit dem letzten Parameter können Sie auch eine interne DTD definieren, die sich also direkt im XML-Dokument befindet. Die hier übergebenen Daten werden direkt eingefügt, ohne geprüft zu werden.
echo XML_Util::getDocTypeDeclaration("personen", "personen.dtd"); // Ausgabe: <!DOCTYPE personen SYSTEM "personen.dtd"> $DTD='<!ELEMENT personen (person+)> <!ELEMENT person (#PCDATA)>'; echo XML_Util::getDocTypeDeclaration("personen",null,$DTD); // Ausgabe: // <!DOCTYPE personen [ // <!ELEMENT personen (person+)> // <!ELEMENT person (#PCDATA)> // ]>
Die beiden Member-Funktionen collapseEmptyTags() und splitQualifiedName() fallen ein wenig aus der Reihe, können aber sehr hilfreich sein. collapseEmptyTags() ist in der Lage, leere Elemente durch ihre Kurzschreibweise zu ersetzen, in der sie das schließende Tag direkt beinhalten. Somit wird aus einem <br></br> ein <br />. Die Methode bekommt als ersten Parameter den String übergeben, der manipuliert werden soll. Danach können Sie noch eine Konstante übergeben, die definiert, auf welche Tags die Methode sich beziehen soll. Standardmäßig konvertiert sie alle Arten von Tags, was der Konstante XML_UTIL_COLLAPSE_ALL entspricht. Übergeben Sie allerdings explizit XML_UTIL_COLLAPSE_XHTML_ONLY, werden nur die Tags verändert, die zum XHTML-Standard gehören. Diese Methode kann zum einen Speicherplatz sparen, zum anderen aber auch Darstellungsprobleme im Browser verhindern. So interpretieren Browser ein <p></p> oder ein <br></br> oft deutlich anders als ein <p /> bzw. ein <br />.
splitQualifiedName() kann hilfreich sein, wenn Sie Daten von einer externen Quelle übernehmen und einen Namespace ermitteln wollen. Sie bekommt den Namen eines Tags übergeben und extrahiert den Namespace und den lokalen Namen aus diesen Daten und gibt sie als Array zurück. Das Array besteht dabei aus den beiden Schlüsseln 'namespace' und 'localPart'. Sie können als zweiten Parameter noch einen Default-Namespace übergeben, der dann zurückgegeben wird, wenn im ersten Parameter nur ein lokaler Teil ermittelt werden konnte. Übergeben Sie keinen Default-Namespace und kann im ersten Teil auch kein Namespace ermittelt werden, enthält der Schlüssel 'namespace' den Wert null.