Jul 07

Design und Content perfekt getrennt mit XSLT und PHP-SimpleXML

Tag: Programmierung, WebFrank @ 08:44

1

XSLT (Extensible Stylesheet Language Transformation) ist eine noch recht junge Sprache die aus DSSSL 120hervorgegangen ist. Sie übersetzt einfache XML-Inhalte nach den in der XSLT-Datei festgelegten Regeln in eine Andere Sprache - zumeist HTML. Dazu wird ein sogenannter XSLT Prozessor genutzt der das XML entweder Serverseitig Transformiert und so schon HTML an den Client ausliefert oder der Browser übernimmt diesen Part und übersetzt lokal. Nähere Information bietet hier wie immer die Wikipedia121. Ich zeige hier in erster Linie den Weg über den Browser auf da die Kompatibilität inzwischen in meinen Augen ausreichend ist (IE ab Version 6, Mozilla ab Version 1.0.2).

PHP-SimpleXML ist eine Reihe von Funktionen die PHP anbietet um im XML Dateien aus Objekten zu erzeugen oder Objekte aus XML-Dateien zu erstellen. Dazu bedient sie sich einer DOM Struktur. SimpleXML ist ein Bestandteil von PHP der Version 5 und wird Standardmäßig mitinstalliert. Die meisten Provider bieten diese Funtionen auch an. Weitere Infos bietet hier PHP.net122 selbst.

Was wir hier nun probieren wollen ist mit PHP-SimpleXML XML Dateien zu erzeugen die dann mit XSLT Dargestellt werden. Erfahrungen mit PHP, HTML, CSS und XML an sich sind dabei vorausgesetzt. Ziel ist es eine Nutzerliste wie sie zum Beispiel in einem Forum zu sehen wäre anzuzeigen. Die Möglichkeiten sind natürlich unendlich ;o) .

XML erzeugen mit PHP-SimpleXML

Zunächst wird ein neues SimpleXML Objekt erzeugt.

$xmlstr =  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
$xmlstr .= "<?xml-stylesheet type=\"text/xsl\" href=\"nutzerliste.xsl\"?>";
$xmlstr .= "<NUTZERLISTE>";
$xmlstr .= "</NUTZERLISTE>";
$xml = new SimpleXMLElement($xmlstr);

Dies geschieht mit new SimpleXMLElement dem ein fertiger XML-String übergeben wird. In diesem Fall ist das die Standard XML-Definition, gefolgt von der Angabe des XSLT-Skripts und der Definition eines Elements. Nun werden einige Nutzer angelegt. Dazu würde man sich im Normalfall wahrscheinlich eine Datenbankanfrage bedienen - da dies aber nur ein Beispiel ist zeihe ich hier folgendes Array heran:

$nutzerarray = array();
$nutzerarray[0] = array('name' => 'Ralf', 'wohnort' => 'Dortmund', 'geburtstag' => '25.09.1962');
$nutzerarray[1] = array('name' => 'Stefan', 'wohnort' => 'Berlin', 'geburtstag' => '06.06.1981');
$nutzerarray[2] = array('name' => 'Georg', 'wohnort' => 'Pirna', 'geburtstag' => '13.06.1951');
$nutzerarray[3] = array('name' => 'Maik', 'wohnort' => 'Dresden', 'geburtstag' => '15.04.1969');

Jetzt wir das Array mit einer passenden Schleife durchlaufen um mit Hilfe der von SimpleXML gegebenen Funktionen um dazu jeweils ein Element im in der Nutzerliste zu erzeugen. Dazu nutze ich in erster Linie die PHP-Funktion addChild mit der zunächst an meine Haupt-XML-Klasseninstanz einen neuen Zweig angehängt wird. Als Ergebnis daraus erhalte ich eine neue Klasseninstanz im Objekt $nutzerobject welche mir nun erlaubt diesen neuen Zweig zu verändern. Dabei werden wiederum addChild Funktionen genutzt um den eigentlichen Inhalt einzufügen. Natürlich könnte man hier auch mit Attributen des Zweigs arbeiten - dies würde diese Anleitung aber unnötig kompliziert machen.

foreach($nutzerarray as $nutzer)
    {
$nutzerobject = $xml->addChild("NUTZER");
$nutzerobject->addChild("NAME", $nutzer[name]);
$nutzerobject->addChild("WOHNORT", $nutzer[wohnort]);
$nutzerobject->addChild("GEBURTSTAG", $nutzer[geburtstag]);
}

Wenn das XML-File nun ausgegeben wird finden wir eine Wohlgeformte XML Struktur, die aber mangels XSLT noch nicht sehr Anschaulich aussieht (Grün). Wichtig ist - da wir den XML-Baum ja dynamisch mit einer PHP Datei erzeugen eine passende Headerinformation mitzusenden die dem Browser verrät das es sich hierbei nicht um eine einfaches Textfile sondern um XML Inhalte handelt.

header('Content-Type: text/xml');
echo $xml->asXML();
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="nutzerliste.xsl"?>
<NUTZERLISTE>
    <NUTZER>
        <NAME>Ralf</NAME>
        <WOHNORT>Dortmund</WOHNORT>
        <GEBURTSTAG>25.09.1962</GEBURTSTAG>
    </NUTZER>
    <NUTZER>
        <NAME>Stefan</NAME>
        <WOHNORT>Berlin</WOHNORT>
        <GEBURTSTAG>06.06.1981</GEBURTSTAG>
    </NUTZER>
    <NUTZER>
        <NAME>Georg</NAME>
        <WOHNORT>Pirna</WOHNORT>
        <GEBURTSTAG>13.06.1951</GEBURTSTAG>
    </NUTZER>
    <NUTZER>
        <NAME>Maik</NAME>
        <WOHNORT>Dresden</WOHNORT>
        <GEBURTSTAG>15.04.1969</GEBURTSTAG>
    </NUTZER>
</NUTZERLISTE>

Dies ist der erzeugte XML-Code der in der Browserausgabe natürlich noch nicht so umwerfend aussieht. Im unterschied zu normalen Inhalten haben wir bis zu diesem Zeitpunkt aber noch kein Stückchen HTML gebraucht. und mussten uns darüber auch keine sorgen machen wie das ganze später mal aussieht. Für andere Programme ist es dank XML ein leichtes darauf zuzugreifen.

Aus XML werde HTML

Um dies nun Optisch anschaulicher zu machen wird sich des XSLT bedient um eine Sinnvolle Ausgabe zu erzeugen. Wie bereits in der XML-Stylesheet Definition festgelegt wurde benötigen wir dazu die Datei nutzerliste.xsl. Zunächst der nötige Kopfteil:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />

Wie gewohnt wird also zunächst die XML-Version und das Encoding bestimmt. Für XSL muss der Namespace und die “Ausgabesprache” HTML festgelegt werden.

<xsl:template match="/NUTZERLISTE">

Jetzt geht es schon mit den XSL-Befehlen los. NUTZERLISTE wird als Hauptzweig festgelegt. Dies verhält sich wie ein Filter. Die in diesem Zweig festgelegten Regeln werden nur angewandt wenn der Hauptzweig NUTZERLISTE heißt. Um nun aber zum HTML zu kommen kann in diesem Bereich Ganz normal mir allen HTML Elementen gearbeitet werden.

<html>
<body>

<table>

Natürlich muss dabei auch eine normale HTML Deklaration erfolgen. In diesem Fall lege ich im Header nichts fest - es wäre hier aber gut möglich auch ein CSS-Stylesheet anzugeben um das Design noch ein wenig dynamischer zu gestalten.

<xsl:for-each select="NUTZER">
<tr>
 <td><strong>Name:</strong></td>         <td><xsl:value-of select="NAME" /></td>
 <td><strong>Wohnort:</strong></td>      <td><xsl:value-of select="WOHNORT" /></td>
 <td><strong>Geburtstag:</strong></td>   <td><xsl:value-of select="GEBURTSTAG" /></td>
</tr>
</xsl:for-each>

XSL Stellt ganz normale Schleifen zur Verfügung wie sie bei anderen Programmiersprachen auch bekannt sind. In diesem Fall wird mit xsl:for-each für jenen Nutzer Zweig der eingeschlossene Code ausgeführt. Dabei wird eine Tabellenzeile erstellt die mit Hilfe von xsl:value-of mit Werten gefüllt wird. Eine logische Angelegenheit eigentlich.

</table>
</body>
</html>
</xsl:template>

</xsl:stylesheet>

Die vielen geöffneten tags müssen natürlich noch geschlossen werden. Ein abschließender Aufruf der zuvor erzeugten PHP-Datei ist vom Browser gemäß den Festgelegten Regeln formatiert Der Zurück gelieferte Quelltext ist noch immer reinstes XML und vollkommen unabhängig vom Design. Die wichtigsten Werkzeuge um beispielsweise ein Templatingsystem für einen Blog zu implementieren hätten wir so im Prinzip schon in der Hand. Doch das ist noch nicht alles - XSL ist noch viel mächtiger.

Grenzenlos mit XSL

XSL kann die zurück gelieferten XML Inhalte nicht einfach nur wiedergeben sondern auch sinnvoll auswerten. Dies kann zum einen Sinnvoll sein im bestimmte Designelemente eben nur anzuzeigen wenn sie Tatsächlich einen Einhalt haben (Leerer Warenkorb?), um Abstufungen zu bieten (Fortschrittsbalken) oder gar um Fremdquellen auszuwerten.

Nachfolgend eine Angepasste Version der Zählschleife von oben:

Insgesamt <xsl:value-of select="count(NUTZER)"/> Einträge
<table>
<xsl:for-each select="NUTZER">
<xsl:if test="starts-with(WOHNORT, 'D')">
<tr>
<td><strong>Name:</strong></td>         <td><xsl:value-of select="NAME" /></td>
<td><strong>Wohnort:</strong></td>      <td><xsl:value-of select="WOHNORT" /></td>
<td><strong>Geburtstag:</strong></td>   <td><xsl:value-of select="GEBURTSTAG" /></td>
</tr>
</xsl:if>
</xsl:for-each>
</table>

Hier ist zunächst eine spezielles value-of dazu gekommen was mit count() Ausgibt wie viele Nutzer wir denn insgesamt haben. Zudem wurde in der for-each Schleife Ein xsl:if hinzugefügt. Diesem wird eine Bedingung mitgegeben und falls diese Wahr ist werden die darin liegenden Regeln ausgeführt. In diesem Fall muss der Wohnort mit ‘D’ beginnen.

Die Ausgabe ist jetzt zunächst eine Angabe wie viele Einträge sich im Array befinden und dann wie bereits vorher die Nutzer - nur das diesmal nur die beiden Einträge bei denen der Wohnort mit ‘D’ anfängt angezeigt werden.

<xsl:for-each select="NUTZER">
<xsl:sort select="WOHNORT"/>
<tr>
<td><strong>Name:</strong></td>         <td><xsl:value-of select="NAME" /></td>
<td><strong>Wohnort:</strong></td>      <td><xsl:value-of select="WOHNORT" /></td>
<td><strong>Geburtstag:</strong></td>   <td><xsl:value-of select="GEBURTSTAG" /></td>
</tr>
</xsl:for-each>

Eine weitere Praktische Funktion ist das Sortieren - xsl:sort ist ein Kindelement der for-each Schleife und Bestimmt dessen Sortierung - in diesem Fall wird nach dem Wohnort in Alphabetischer Reihenfolge Sortiert - möglich wäre hier aber auch mit order=”descending” zum Beispiel eine umgekehrte Sortierung und Ähnliches. Der Befehl kann auch mehrfach hintereinander eingesetzt werden falls sich zum Beispiel ein Ortsname doppelt und dann nach Name sortiert werden soll.

Mehr, mehr, mehr!

… gibt es zum Beispiel auf data2type.de123 und auf xml-xslt.de124. Hier gibt es ein XSLT-Tutorial125 sowie eine Befehlsreferenz (von data2type.de126 sowie etwas umfassender von xml-xslt.de127). Des weiteren gibt es ein schönes Buch von Doug Tidwell welches man zum “auf den Geschmack kommen” auch Online einsehen128 kann. Dies waren im großen und ganzen auch meine Hauptquellen für diesen Artikel. Ansonsten sind Informationen hierzu eher weitläufig gestreut - besonders im Bezug auf Test-Funktionen. Aber im Allgemeinen findet man dank Google schon was man sucht.

Weitere interessante Links:

Dateien aus diesem Beispiel:

XSLT bietet eine der wenigen Möglichkeiten Design und Content in PHP wirklich vollkommen von einander zu trennen. Im PHP-Code muss sich kein Stück HTML-Code befinden. Wenn nun noch alle Eingabewerte vernünftig gefiltert werden steht der sicheren Programmierung nichts mehr im Wege. Auf jeden Fall ein Thema mit dem sich jeder ambitionierte Webdesigner mal näher beschäftigen sollte.

Schreib einen Kommentar

*
Um sicherzustellen das du kein Bot bist gib diesen Code ein.
Anti-Spam Image