Artikelformat

xsl als Templatesystem

Obwohl PHP als Template-Sprache entworfen wurde, gibt es inzwischen viele Templatesysteme, die in PHP geschrieben sind. Diese stellen Daten bspw. als HTML-Code dar. Dieser Beitrag befasst sich nun mit dem Two Step View Design Pattern, das in PHP umgesetzt werden kann und dabei fast kein PHP nutzt. Dieser Widerspruch wird nun aufgeklärt.

Das Pattern beschreibt eine 2 stufige Transformation von Daten zu einer fertigen Ausgabe. Zuerst werden die Daten aus der Datenbank gelesen und in der Business Logik errechnet. Es besteht die Möglichkeit verschiedene Datenquellen anzuzapfen. Wichtig ist nur, dass die aggregierten Daten in einer domänspezifischen XML Repräsentation existieren. Diese Daten werden nun in einem ersten Schritt aufbereitet, wodurch ein neues XML-Dokument entsteht. Beispielsweise für eine Ausgabe auf dem Bildschirm. Diese Zwischenstufe ist noch kein fertiges HTML. Erst im zweiten Schritt wird dieses Zwischendokument in HTML transformiert.
Der Vorteil dieser Vorgehensweise liegt darin, dass man so nur das Template definieren muss dabei eigene Tags zur Verfügung hat. Damit können komplexe Strukturen durch ein simples Tag ausgedrückt werden. Auch kann man die vorhandenen HTML Tags um eigene erweitern. Bspw ein Kalendar-Input Feld o.ä. Durch die Benutzung vorgegebener Komponenten kann man auch ein Design definieren, dass die gesamte Webapplikation oder Webseite nutzt. Es entsteht also ein einheitliches Design und Layout.
Ein weiterer Vorteil ist die mehrfache Nutzung der domänspezifischen Daten. Mit Hilfe alternativer Layout-Informationen lässt sich eine andere Art der Ausgabe generieren. PDF- oder Excel-Dateien sind theoretisch möglich.

Soviel zur Theorie. Im folgenden gibt es eine simple Beispielimplementierung.

Zuerst gibt es die Daten. Diese sind in diesem Fall als XML-Datei abgelegt. In einem echten System würde man DOMDocument, XMLWriter oder SimpleXML nutzen, um die Daten aus der Businesslogik in XML-darzustellen. Im Beispiel heißt der Root-Knoten array. Darin gibt es row– und cell-Tags. So kann ein 2-dimensionales Array dargestellt werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="UTF-8"?> 
<array>
    <row> 
        <cell>14</cell>
        <cell>17</cell>
        <cell>13</cell>
        <cell>12</cell>
        <cell>11</cell>
        <cell>16</cell>
        <cell>14</cell>
        <cell>11</cell>
    </row> 
    <row> 
        <cell>24</cell>
        <cell>27</cell>
        <cell>23</cell>
        <cell>22</cell>
        <cell>21</cell>
        <cell>26</cell>
        <cell>24</cell>
        <cell>21</cell>
    </row>
    <row> 
        <cell>34</cell>
        <cell>37</cell>
        <cell>33</cell>
        <cell>32</cell>
        <cell>31</cell>
        <cell>36</cell>
        <cell>34</cell>
        <cell>31</cell>
    </row>
</array>

Die definierten Daten werden durch ein xsl-Template transformiert und es entsteht die abstrakte Beschreibung eines Layouts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8"/> 
    <xsl:template match="/array">
        <layout> 
            <simplelist>
                <xsl:for-each select="row"> 
                    <block>
                        <xsl:for-each select="cell"> 
                            <data>
                                <xsl:value-of select="."/> 
                            </data>
                        </xsl:for-each> 
                    </block>
                </xsl:for-each> 
            </simplelist>
        </layout> 
    </xsl:template>
</xsl:stylesheet>

Die nun vorhandene Beschreibung wird im zweiten Schritt in HTML-Code umgewandelt. Man erhält eine HTML-Datei mit Header, Body und einer Tabelle mit den eingangs gezeigten Daten.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" />
    <xsl:template match="/layout"> 
        <html>
            <head> 
                <title>XSL Test</title>
            </head> 
            <body>
                <xsl:apply-templates/> 
            </body>
        </html> 
    </xsl:template>
    <xsl:template match="simplelist"> 
        <table border="1">
            <xsl:apply-templates/> 
        </table>
    </xsl:template>
    <xsl:template match="block"> 
        <tr>
            <xsl:apply-templates/> 
        </tr>
    </xsl:template>
    <xsl:template match="data"> 
        <td>
            <xsl:apply-templates/> 
        </td>
    </xsl:template> 
</xsl:stylesheet>

PHP bietet mit der XSLTProcessor-Klasse einen guten Zugang zu den XSL-Transformationen. Eine einfache Two-Step-View Implementierung ist der folgende HTMLGenerator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class HTMLGenerator {
 
    /**
     * Führt die Template, Layout und Daten zusammen und generiert einen Ausgabe-String
     *
     * @param DOMDocument $data
     * @param DOMDocument $data2layout
     * @param DOMDocument $layout2html
     * @return String  
     */
    public static function execute(DOMDocument $data, DOMDocument $data2layout, DOMDocument $layout2html) {
 
        // Daten nach Layout - Prozessor erzeugen
        $data2layout_proc = new XSLTProcessor;
        // Spezifisches Stylesheet einlesen 
        $data2layout_proc->importStyleSheet($data2layout);
        // Erste Transformation durchführen 
        $layout = $data2layout_proc->transformToXML($data);
        // Layout nach Präsentation - Prozessor erzeugen
        $layout2html_proc = new XSLTProcessor;
        // Allgemeines Layout Stylesheet einlesen 
        $layout2html_proc->importStyleSheet($layout2html);
        // Zweite Transformation durchführen 
        $pres = $layout2html_proc->transformToXML(DOMDocument::loadXML($layout));
        // Rückgabe des fertigen Präsentationscodes
        return $pres;
    }
 
}

Der Vorteil von XSL ist, dass man dieses Verfahren mit jeder Programmiersprache einsetzen kann, die einen XSLTProzessor mitbringt. Und dabei können Template- und Layout-Dateien ohne Aufwand migriert werden. Man benötigt nur eine ähnliche Implementierung wie der HTMLGenerator und Logik, die die XML-Daten generiert.

Das Beispiel ist (inkl. index.php) wie gewöhnlich im SVN-Repository zu finden.

11 Kommentare

  1. Es gibt aber auch ein paar Gefahren mit XSLT.
    Zum einen sollte es nie (!) on-the-fly eingesetzt werden, denn es ist sehr langsam und rechen-intensiv.
    Zum anderen werden XSL Dateien gerade in groesseren Projekten sehr schnell sehr unwartbar.
    Ich habe vor Jahren mal in einem Projekt via XSLT Produkt Kataloge aus einer Webdatenbank in PDF gewandelt inkl Bilder, Seitenumbruechen etc. Geht alles ganz toll. XSL ist sogar einigermassen modular zu schreiben und ich kann auf jede Menge Bedingungen unterschiedlich agieren. Ploetzlich aber hat man viele XSL Dateien, die alle unglaublich aehnlich aussehen und die innerhalb kuerzester Zeit keiner mehr versteht.
    Sicher gibt es Anwendungsfaelle, wo XSLT eine gute Wahl ist, aber das sollte wohl ueberlegt sein.

    Antworten
    • Ich habe an einem Framework mitgearbeitet, dass die Templates per XSL realisiert. Bei dem Profiling war die Zeit für die Generierung immer weit unter der für die DB Zugriffe und Berechnungen. Vielleicht hätte man mit einem anderen Templatesystem etwas mehr Performance erreicht, aber diese wäre wohl nur bei einer sehr hohen Last zum Tragen gekommen. Und ich gebe dir recht. Die Wartung kann mühsam sein, insbesondere wenn die Layout-Dateien, die im 2. Step benutzt werden, nicht sauber getrennt und kommentiert sind. Auf der anderen Seite kann man auch mit Smarty oder Twig Templates bauen, die später nur noch schwer zu durchschauen sind.

  2. Zitat: „Zum einen sollte es nie (!) on-the-fly eingesetzt werden, denn es ist sehr langsam und rechen-intensiv.“ (Christian)

    Das ist doch Unsinn. Lass das Ganze durch einen ordentlichen Prozessor laufen und das Ding rennt.
    Wenn deine XSL-Dateien so riesig werden, dann machst du sowieso etwas falsch. Und wenn deine eigenen Dateien nicht mehr verstehst, dann läuft ebenfalls etwas falsch!

    Wenn es tatsächlich um gewaltige Mengen an Daten und Verarbeitungsprozesse geht, dann wäre wahrscheonlich XSLT 2.0 ratsam.

    Zitat: „Papaya CMS verwendet diese Template-Technik.“ (David)

    Es ist nicht nur einfach „diese“ Template-Technik, sondern „die“ Template-Technik überhaupt. Der Rest à la SilverStripe & Co. sind doch nur Insellösungen und eigene Erfindungen. XSLT ist ein Standard des W3Cs.

    Antworten
  3. Guter Beitrag. Allerdings bin ich auch nicht so der XSLT-Anhänger.
    Dort wo ich arbeite verwenden wir momentan auch noch XSLT-Templates.
    Wie aber schon erwähnt wurde, kann das ganze sehr Rechenintensiv werden und zudem schlecht wartbar.
    Das schlecht wartbare ist aber in so ziemlich jedem System gegeben, wenn man nicht sehr gut aufpasst.
    Über das Rechenintensive lässt sich streiten. Klar ist ein DB-Zugriff langsamer und sollte in erster Linie bei Performance-Problemen angeschaut werden. Allerdings denke ich, dass man ohne DB-Zugriffe vielfach nicht auskommt, ohne XSLT hingegeben schon.

    Was mich auch stört an XSLT ist die fehlenden Funktionen. Man muss zum Teil schon viel im Controller/Model View-gerecht aufbereiten, bevor man es wirklich benutzen kann im XSLT.

    Wenn man nur PHP-Templates hat hat man dieses Problem nicht. Einen Helper für solche View-Formatierungen schreiben und somit hat man solche Probleme nicht mehr (und ist erst noch einigermassen schön und wiederverwendbar gemacht).

    Daher bin ich mitlerweile sehr Fan von schlichten PHP-Templates ohne irgendwelche andere Engines.
    Ist die schnellste Variante und meiner Meinung nach am praktikabelsten.
    Damits auch noch lesbar bleibt kann man z.B. die Statements mit der alternativen Syntax schreiben:
    if ($foo == ‚bar‘):
    echo ‚foobar‘;
    endif;

    Somit wird das auch über mehrere Zeilen noch lesbar.

    Antworten
  4. Hmm, der Quelltext ist der gleiche wie in dem Artikel „XSL als alternatives Templatesystem“ von Norbert Bartels und Hans-Jörg Peter
    PHP Solutions, Ausgabe 4/2008 (Seite 156-160)

    Antworten
  5. Ich arbeite seit einigen Jahren mit XSL und für mich wird es – zumindest im großen Stile – keine andere Template Engine für meine Projekte geben.

    Selbstverständlich wird es bei vielen Dateien unübersichtlich, aber durch eine gute Namenskonvention – die sich durch all meine Projekte zieht – spielt dies überhaupt keine Rolle.

    Zur Geschwindigkeit: Bei mir kann das Template – nach dem es bearbeitet wurde – neu „eingelesen“ werden. D.h., in diesem Zug verarbeitet der Processor das ganze und speichert das fertige Dokument (außer dynamische Inhalte natürlich) als Cache in der Datenbank. Von dort wird dann die Website ausgegeben.

    Läuft einwandfrei, Geschwindigkeit top.

    Antworten

Schreibe einen Kommentar

Pflichtfelder sind mit * markiert.