Die Idee der Extensible Server Pages ist nicht neu: Innerhalb von XML-Seiten wird Programmcode untergebracht, der in dem Moment ausgeführt wird, in dem ein Web-Browser darauf zugreift. Es ist das gleiche Prinzip wie bei Server Side Includes (SSI), PHP oder auch bei serverseitigem JavaScript. Diese Vorgehensweise verletzt die strikte Trennung von Inhalt, Strukur und Verarbeitung, die eine wesentliche Eigenschaft von SGML und XML sein sollte. Wir werden später an einem ausführlichen Beispiel zeigen, wie man seine XML-Dokumente frei hält von dem eingebetteten Programmcode und dennoch die Vorteile von XSP nutzt.
Um die Funktionsweise von Cocoons XSP-Prozessor zu veranschaulichen, beginnen wir aber mit einigen kleinen Beispielen aus der XSP-Dokumentation. Das folgende Beispiel zeigt eine erste XSP-Seite, die eine HTML-Seite mit dynamisch generiertem Inhalt erzeugt.
<?xml version="1.0"?> <?cocoon-process type="xsp"?> <xsp:page language="java" xmlns:xsp="http://www.apache.org/1999/XSP/Core"> <xsp:structure> <xsp:include>java.text.SimpleDateFormat</xsp:include> </xsp:structure> <html> <head><title>Hallo</title></head> <body> <p>Guten <xsp:logic> String timeOfDay = ( new SimpleDateFormat("aa") ).format(new Date()); if (timeOfDay.equals("AM")) { <xsp:content>Morgen</xsp:content> } else { <xsp:content>Tag</xsp:content> } </xsp:logic>! </p> </body> </html> </xsp:page>
Je nach der momentanen Tageszeit erzeugt diese Seite
entweder die Ausgabe Guten Morgen!
oder Guten
Tag!
. Der wesentliche Teil steht dabei innerhalb von
<xsp:logic> und
</xsp:logic>. Darin befindet sich (in diesem
Beispiel) ein kleines Java-Programm, das entweder den Text
Morgen
oder Tag
ausgibt. Eingebettet ist die
gesamte Seite in das Element xsp:page. Das Element xsp:include importiert die hier
benötigte Java-Bibliothek
java.text.SimpleDateFormat. Es muss innerhalb eines
xsp:structure-Elements
stehen. Als Ergebnis des obigen Beispiels ergibt sich (nachmittags)
folgende
HTML-Seite:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html> <head><title>Hallo</title></head> <body> <p>Guten Tag! </p> </body> </html> <!-- This page was served in 6282 milliseconds by Cocoon 1.6.1 -->
Die abschreckende Zeitangabe entstand auf einer Sun
Ultra 10 mit einer 299 MHz
UltraSPARC-IIi CPU mit 128
MByte Hauptspeicher. Trotz dieser Hardware brauchte Cocoon so
lange, weil aus der XSP-Seite ein Java-Class-File
compiliert wurdeUnter dem Gesichtspunkt der
Geschwindigkeit ist hier auch noch von Interesse, dass die
Dateien auf eine Platte geschrieben wurden,
auf die per NFS zugegriffen wurde. Insgesamt war
die Testumgebung also nicht
performance-optimiert.. Ist diese Arbeit einmal
getan, laufen
spätere Zugriffe schneller ab.
Das folgende Listing zeigt die DTD für XSP, wobei angenommen wird, dass der Leser in der Lage ist, DTDs zu lesen. Es schließt sich eine Beschreibung der momentan brauchbaren Elemente an. Die DTD stammt aus dem XSP Working Draft von der Apache-Site. Er beschreibt auch geplante, zukünftige Eigenschaften der XSP. Aus diesem Grund enthält die DTD auch noch einige ungenutzte und undokumentierte Elementtypen. Des Weiteren ist in der aktuellen Situation zu beklagen, dass eine Validierung gar nicht möglich ist, da in XSP wie auch in XSLT Gebrauch von den Namensräumen gemacht wird. Der Begriff der Gültigkeit von Multi-DTD- oder Multi-Namensraum-Instanzen ist aber erst einmal gar nicht definiert; XML 1.0 kennt ihn nicht. In diesem Bereich werden die Bemühungen der Schema-Arbeitsgruppe hoffentlich eine Lösung liefern.
<!ENTITY % elements "xsp:expr | xsp:element | xsp:pi | xsp:comment"> <!ELEMENT xsp:page (xsp:structure?, xsp:logic?, xsp:content)> <!ATTLIST xsp:page language CDATA #REQUIRED indent-result (yes|no) "no" xmlns:xsp CDATA #FIXED "http://www.apache.org/1999/XSP/Core" xml:space (default|preserve) "preserve" > <!ELEMENT xsp:structure (xsp:dtd?, xsp:include*)> <!ELEMENT xsp:dtd (#PCDATA)> <!ELEMENT xsp:include (#PCDATA)> <!ELEMENT xsp:content (#PCDATA | xsp:logic | %elements;)*> <!ELEMENT xsp:logic (#PCDATA | xsp:content | %element;)*> <!ATTLIST xsp:logic xml:space (default|preserve) "preserve"> <!ELEMENT xsp:element (#PCDATA | xsp:attribute | xsp:element | xsp:logic)*> <!ATTLIST xsp:element name CDATA #REQUIRED> <!ELEMENT xsp:attribute (#PCDATA)> <!ATTLIST xsp:attribute name CDATA #REQUIRED xml:space (default|preserve) "preserve"> <!ELEMENT xsp:pi (#PCDATA | xsp:expr> <!ELEMENT xsp:comment (#PCDATA | xsp:expr)> <!ELEMENT xsp:expr (#PCDATA)>
Beschreibung der wichtigsten Elementtypen:
Das Element xsp:page ist das Wurzelelement einer XSP-Instanz. Es verlangt zwingend die Angabe einer Programmiersprache; im Fall von Cocoon wird java unterstützt. Der XSP-Namensraum muss in der angegebenen Weise auch in der Instanz stehen, weitere Namensraumangaben dürfen natürlich ergänzt werden.
Direkte Nachfahren des Typs xsp:logic enthalten Programmcode auf Ebene einer Klasse, das heißt die Deklaration von Feldern und Methoden.
Processing Instructions der obersten Ebene bleiben bei der Verarbeitung durch den XSP-Prozessor erhalten. Dies ist für eine nachfolgende Verarbeitung, etwa durch die XSLT-Maschine, nützlich.
Dieses Element nimmt die Elemente vom Typ xsp:include auf, die dazu dienen, in einer sprachunabhängigen Weise, Sprachbibliotheken zu laden. Folgende Java-Pakete werden automatisch geladen:
xsp:logic enthält Programmcode, der wörtlich in das generierte und später ausgeführte Programm übernommen wird. Das Element xsp:content dient dazu, Inhalt des umgebenden Stylesheets in xsp:logic einzubetten. Die Wirkung ist die gleiche als ob vor xsp:content das Element xsp:logic geschlossen würde, dann käme der Inhalt des Content-Elements und anschließend würde ein neues Logic-Element beginnen.
Diese Elementtypen dienen dazu, Elemente und Attribute, deren Namen über das gleichnamige Attribut angegeben wird, in einer Instanz zu erzeugen. Der Nutzen ist momentan noch beschränkt. In Zukunft sollen Ausdrücke wie der folgende möglich sein:
<xsp:element name='{ordered ? "ol" : "ul"}'> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </xsp:element>
Zurzeit bietet die XSP-Dokumentation einzig eine programmgesteuerte Alternative an, die folgendermaßen aussieht:
<xsp:logic> String tagName = null; if (ordered) { tagName = "ol"; } else { tagName = "ul"; } xspParentElement = xspCurrentElement; xspNodeStack.push(xspParentElement); xspCurrentElement = document.createElement(tagName); </xsp:logic> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <xsp:logic> xspCurrentElement = (Node) xspNodeStack.pop(); </xsp:logic>
Die Bezeichnung für die XSP-Bibliotheken
lautet in der Original-Dokumentation Tag
Libraries
. Dahinter verbirgt sich die Möglichkeit,
Elementtypen mit einer bestimmten Funktion zu belegen und
diese Funktion extern zu definieren. Zur
Veranschaulichung folgendes
Beispiel als Zitat aus der Dokumentation:
<?xml version="1.0"?> <?cocoon-process type="xsp"?> <?cocoon-process type="xslt"?> <?xml-stylesheet href="sample.xsl" type="text/xsl"?> <xsp:page language="java" xmlns:xsp="http://www.apache.org/1999/XSP/Core" xmlns:example="http://www.plenix.com/DTD/XSP/Example" > <page title="Time of Day"> <p> To the best of my knowledge, it's now <!-- Substitute time of day here --> <example:time-of-day format="yy/MM/dd hh:mm:ss aa"/> </p> </page> </xsp:page>
In diesem Beispiel wird ein neuer Namensraum example deklariert. Verwendet wird die Bibliothek in Form des Elements example:time-of-day. Für die Realisierung der Bibliothek gibt es nicht etwa eine eigene Sprache; stattdessen kommt einmal mehr XSLT zum Einsatz. Ein Stylesheet hat die Aufgabe, das Element example:time-of-day mit Leben zu füllen. Dazu muss das Stylesheet einerseits die aktuelle Uhrzeit als Wert des Elements einfügen (und dazu benötigten Programmcode ebenfalls), andererseits aber auch alle Ursprungselemente in obigem Listing unverändert lassen. Diese Aufgabe erfüllt das folgende Listing, ebenfalls aus der XSP-Dokumentation zitiert:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsp="http://www.apache.org/1999/XSP/Core" xmlns:example="http://www.plenix.com/DTD/XSP/Example"> <xsl:template match="xsp:page"> <xsp:page> <xsl:copy> <xsl:apply-templates select="@*"/> </xsl:copy> <xsp:structure> <xsp:include>java.util.Date</xsp:include> <xsp:include>java.text.SimpleDateFormat</xsp:include> </xsp:structure> <xsp:logic> /* "Example" Class Level Logic */ private static String formatDate(Date date, String pattern) { if (pattern == null || pattern.length() == 0) { pattern = "yyyy/MM/dd hh:mm:ss aa"; } return (new SimpleDateFormat(pattern)).format(date); } </xsp:logic> <xsl:apply-templates/> </xsp:page> </xsl:template> <xsl:template match="example:time-of-day"> <xsp:expr> formatDate(new Date(), "<xsl:value-of select="@format"/>") </xsp:expr> </xsl:template> <xsl:template match="@*|node()" priority="-1"> <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy> </xsl:template> </xsl:stylesheet>
Wie Sie sehen können, die Einsatzmöglichkeiten von XSLT sind innerhalb von Cocoon sehr vielfältig und erlauben eine sehr flexible Aufgabenlösung.
In diesem Abschnitt möchten wir Ihnen ein
XSP-Beispiel im Detail zeigen. Das Beispiel ist
von der Java-Programmierung betrachtet sehr simpel, aber es
verdeutlicht, wie XSP eingesetzt werden kann,
ohne das XML-Dokument mit Programmcode zu
verunreinigen
. Den Ausgangspunkt bildet die folgende
XML-Instanz mit eingebetteter
DTD.
<?xml version="1.0"?> <?xml-stylesheet href="notiz2html.xslt" type="text/xsl"?> <?cocoon-process type="xslt"?> <!DOCTYPE notiz [ <!ELEMENT notiz (titel, autor, datum, absatz+) > <!ELEMENT titel (#PCDATA) > <!ELEMENT autor (#PCDATA) > <!ELEMENT datum (#PCDATA) > <!ELEMENT absatz (#PCDATA | wichtig)* > <!ELEMENT wichtig (#PCDATA) > ]> <notiz> <titel>Termine</titel> <autor>Weihnachtsmann</autor> <datum>24. Dezember</datum> <absatz>Nicht vergessen: <wichtig>Geschenke austeilen</wichtig> </absatz> <absatz> ... </absatz> </notiz>
Das Beispiel ist so einfach, dass man es kaum
erklären muss. Wir haben hier einen Dokumenttyp für eine
Notiz
, die aus einem Titel, einem Autor, einem Datum
sowie einem oder mehreren Absätzen besteht. Innerhalb der
Absätze können Textstellen als wichtig
markiert
werden.
Um solche Notizen nun im Web-Browser darstellen zu können, brauchen wir ein XSLT-Stylesheet, das den XML-Code in HTML wandelt. Die für Cocoon wichtigen Processing Instructions sind im Dokument bereits vorhanden. Die Stylesheet-PI verknüpft die Instanz mit notiz2html.xslt, das im folgenden Listing zu sehen ist:
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- © 2000 Stefan Mintert --> <!-- ====================================================== --> <!-- Template fuer Root-Element 'notiz' --> <xsl:template match="notiz"> <xsl:processing-instruction name="cocoon-format">type="text/html"</xsl:processing-instruction> <html> <head> <title>Notiz</title> <style type="text/css"> <!-- body { text-align: center; background: #cccccc; } table { padding: 1ex; } div.framed { margin-left: 20%; margin-right: 20%; margin-top: 4ex; background: white; border: solid medium black; } span.titel { font-size: 200%; } .autor { color: #0000cc; font-weight: bold; } .datum { color: #00cc00; text-weight: bold; } .wichtig { color: white; background: red; } address { margin-top: 2ex; } --> </style> </head> <body> <div class="framed"> <table> <xsl:apply-templates/> </table> </div> <address> Copyright © 2000 <a href="http://www.mintert.com/">Stefan Mintert</a>.<br /> <a href="http://www.mintert.com/xml/">XML in der Praxis</a><br /> </address> </body> </html> </xsl:template> <!-- ====================================================== --> <!-- ====================================================== --> <!-- Template fuer Elementtyp 'titel' --> <xsl:template match="titel"> <tr> <th colspan="2"> <span class="titel"><xsl:apply-templates/></span> </th> </tr> </xsl:template> <!-- ====================================================== --> <!-- ====================================================== --> <!-- Template fuer Elementtyp 'autor' --> <xsl:template match="autor"> <tr> <td align="right">von</td> <td> <span class="autor"><xsl:apply-templates/></span> </td> </tr> </xsl:template> <!-- ====================================================== --> <!-- ====================================================== --> <!-- Template fuer Elementtyp 'datum' --> <xsl:template match="datum"> <tr> <td align="right">für den</td> <td> <span class="datum"><xsl:apply-templates/></span> </td> </tr> </xsl:template> <!-- ====================================================== --> <!-- ====================================================== --> <!-- Template fuer Elementtyp 'restzeit' --> <xsl:template match="restzeit"> <tr> <td align="right">in</td> <td> <span class="restzeit"><xsl:apply-templates/></span> </td> </tr> </xsl:template> <!-- ====================================================== --> <!-- ====================================================== --> <!-- Template fuer Elementtyp 'absatz' --> <xsl:template match="absatz"> <tr> <td></td> <td> <p class="absatz"> <xsl:apply-templates/> </p> </td> </tr> </xsl:template> <!-- ====================================================== --> <!-- ====================================================== --> <!-- Template fuer Elementtyp 'wichtig' --> <xsl:template match="wichtig"> <span class="wichtig"><xsl:apply-templates/></span> </xsl:template> <!-- ====================================================== --> </xsl:stylesheet>
Das Stylesheet macht aus der Notiz eine einfache
Tabellenform, die mittels eines eingebetteten
CSS optisch noch ein wenig aufbereitet wird. In
einer richtigen
Anwendung sollten die
CSS-Anweisungen besser in einer externen Datei
stehen, damit die gleichen Daten nicht mehrfach vom Browser geladen
werden müssen. Für Demonstrationszwecke können wir
diesen Punkt aber vernachlässigen. Das Resultat der
Cocoon-Verarbeitung ist im nächsten Listing und in
Abbildung
69 zu sehen.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><title>Notiz</title><style type="text/css"> <!-- body { text-align: center; background: #cccccc; } table { padding: 1ex; } div.framed { margin-left: 20%; margin-right: 20%; margin-top: 4ex; background: white; border: solid medium black; } span.titel { font-size: 200%; } .autor { color: #0000cc; font-weight: bold; } .datum { color: #00cc00; text-weight: bold; } .wichtig { color: white; background: red; } address { margin-top: 2ex; } --> </style></head><body><div class="framed"><table> <tr><th colspan="2"><span class="titel">Termine</span></th></tr> <tr><td align="right">von</td><td><span class="autor">Weihnachtsmann</span></td></tr> <tr><td align="right">für den</td><td><span class="datum">24. Dezember</span></td></tr> <tr><td></td><td><p class="absatz">Nicht vergessen: <span class="wichtig">Geschenke austeilen</span> </p></td></tr> <tr><td></td><td><p class="absatz"> ... </p></td></tr> </table></div><address> Copyright © 2000 <a href="http://www.mintert.com/">Stefan Mintert</a>.<br><a href="http://www.mintert.com/xml/">XML in der Praxis</a><br></address></body></html> <!-- This page was served in 3445 milliseconds by Cocoon 1.6.1 -->
Soweit ist die Verarbeitung ganz einfach,
XSP war noch nicht im Spiel. Um nun eine
dynamische Generierung von Daten vorzuführen, muss einmal
mehr das Datum mitspielen. Wir wollen nun nicht nur den
Inhalt des Datum-Elementes anzeigen, sondern zusätzlich
berechnen, wie viele Tage bis zu diesem Termin noch vor uns
liegen. Hier stellt sich zunächst das Problem, dass die
Angabe 24. Dezember
aus obiger Instanz nicht sehr
aussagekräftig ist, weil die Jahresangabe fehlt. Wir
verlangen deshalb, dass das Datum in der Form
TT.MM.JJJJ angegeben wird. In einer
DTD lässt sich diese Bedingung nicht formal
aufschreiben. Es sei nur erwähnt, dass dies in einem
XML-Schema möglich ist. Im nachfolgenden
XML-Dokument steht das Datum nun in der
gewünschten Form. Außerdem haben wir auf die
DTD verzichtet, weil mit Hilfe von
XSP gleich auch noch Transformationen
durchgeführt werden, die dazu führen, dass die Instanz nur
noch wohlgeformt sein wird.
<?xml version="1.0"?> <?cocoon-process type="xslt"?> <?xml-stylesheet href="notiz-xsp.xslt" type="text/xsl"?> <notiz> <titel>Termine</titel> <autor>Weihnachtsmann</autor> <datum>24.12.2000</datum> <absatz>Nicht vergessen: <wichtig>Geschenke austeilen</wichtig> </absatz> <absatz> ... </absatz> </notiz>
Man beachte, dass zur Verarbeitung nun das Stylesheet notiz-xsp.xslt benutzt wird. Wie der Name schon verrät, kommt an dieser Stelle XSP zum Einsatz. Bevor wir Ihnen das Listing zeigen, möchten wir den Ablauf, der durch das Stylesheet realisiert wird, im Überblick darstellen. Die Schritte wie folgt:
Genug der Vorrede, hier ist das Stylesheet notiz-xsp.xslt für Schritt 1:
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsp="http://www.apache.org/1999/XSP/Core"> <!-- © 2000 Stefan Mintert --> <!-- ====================================================== --> <!-- Default-Template: Kopieren der Elemente --> <xsl:template match="*|@*|comment()|text()"> <xsl:copy> <xsl:apply-templates select="*|@*|comment()|text()"/> </xsl:copy> </xsl:template> <!-- ====================================================== --> <!-- ====================================================== --> <!-- Template fuer Element "datum": Kopieren des Elements und Einfuegen von XSP-Logic mit Java-Programmcode --> <xsl:template match="datum"> <datum> <xsl:value-of select="text()"/> </datum> <restzeit> <xsp:logic> Date jetzt = new Date(); DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT,Locale.GERMANY); String terminS = "<xsl:value-of select="text()"/>"; Date termin = new Date(); termin = df.parse(terminS); long tage = (termin.getTime() - jetzt.getTime()) / 1000 / 60 / 60 / 24; </xsp:logic> <xsp:expr>tage</xsp:expr> <xsl:text> Tagen</xsl:text> </restzeit> </xsl:template> <!-- ====================================================== --> <!-- ====================================================== --> <!-- Template fuer Root-Element 'notiz' --> <xsl:template match="notiz"> <!-- Ausgeben der PIs fuer weitere Verarbeitung: Erst XSP, dann XSLT --> <xsl:processing-instruction name="cocoon-process">type="xsp"</xsl:processing-instruction> <xsl:processing-instruction name="cocoon-process">type="xslt"</xsl:processing-instruction> <xsl:processing-instruction name="xml-stylesheet"> href="notiz2html.xslt" type="text/xsl"</xsl:processing-instruction> <!-- Ausgeben des neuen Root-Elements 'xsp:page' --> <xsp:page language="java" xmlns:xsp="http://www.apache.org/1999/XSP/Core"> <!-- Laden der benoetigten Java-Bibliotheken --> <xsp:structure> <xsp:include>java.util.Date</xsp:include> <xsp:include>java.text.DateFormat</xsp:include> </xsp:structure> <!-- Element 'notiz', dass nach der XSP-verarbeitung erzeugt wird --> <notiz> <xsl:apply-templates/> </notiz> </xsp:page> </xsl:template> <!-- ====================================================== --> </xsl:stylesheet>
Wir beginnen die Erklärung mit dem Wurzel-Element notiz, dessen Verarbeitung mit xsl:template match="notiz" eingeleitet wird. Die drei anschließenden Zeilen erzeugen in der Ausgabe Processing Instructions, die Cocoon anweisen, das Resultat dieser Transformation nacheinander mit dem XSP-Prozessor (Schritt 2) und anschließend mit dem XSLT-Prozessor zu behandeln (Schritt 3). Letzterer soll dabei notiz2html.xslt verwenden. In Schritt 1 wird die XSP-Seite generiert, die dann von Cocoon ausgeführt wird. Dies passiert implizit und ist nicht zu erkennen. Natürlich wollten wir Ihnen einen Blick hinter die Kulissen gestatten und haben dazu diesen ersten Schritt manuell ausgeführt. Dazu ist lediglich ein Aufruf der XSLT-Maschine Xalan notwendig. Die Kommandozeile und das Ergebnis von Schritt 1 sehen Sie im nächsten Listing.
sm@brown{442}: java org.apache.xalan.xslt.Process -in notiz2.xml -xsl notiz-xsp.xslt -out schritt1.xml ========= Parsing file:/home/sm/cocoon/dokumente/demo/notiz-xsp.xslt ========== Parse of file:/home/sm/cocoon/dokumente/demo/notiz-xsp.xslt took 1252 milliseconds ========= Parsing notiz2.xml ========== Parse of notiz2.xml took 110 milliseconds encoding not supported: UTF8, using Java 8859_1 ============================= Transforming... transform took 136 milliseconds XSLProcessor: done sm@brown{443}: more schritt1.xml <?cocoon-process type="xsp"?> <?cocoon-process type="xslt"?> <?xml-stylesheet href="notiz2html.xslt" type="text/xsl"?> <xsp:page language="java" xmlns:xsp="http://www.apache.org/1999/XSP/Core"> <xsp:structure> <xsp:include>java.util.Date</xsp:include> <xsp:include>java.text.DateFormat</xsp:include> </xsp:structure> <notiz> <titel>Termine</titel> <autor>Weihnachtsmann</autor> <datum>24.12.2000</datum><restzeit><xsp:logic> Date jetzt = new Date(); DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT,Locale.GERMANY); String terminS = "24.12.2000"; Date termin = new Date(); termin = df.parse(terminS); long tage = (termin.getTime() - jetzt.getTime()) / 1000 / 60 / 60 / 24; </xsp:logic><xsp:expr>tage</xsp:expr> Tagen</restzeit> <absatz>Nicht vergessen: <wichtig>Geschenke austeilen</wichtig> </absatz> <absatz> ... </absatz> </notiz></xsp:page> sm@brown{444}: which more more: aliased to /usr/bin/cat
Bemerkenswert ist hierbei die Zeile String terminS = "24.12.2000". Im ursprünglichen Stylesheet stand dort String terminS = "<xsl:value-of select="text()"/>". Der Ausdruck xsl:value-of wurde also von der XSLT-Maschine ausgewertet. Beachten Sie insbesondere die ungewöhnlich erscheinende Verschachtelung von Anführungszeichen.
Bei diesem Zwischenergebnis handelt es sich also nun um eine xsp:page-Seite, die wieder eine notiz-Instanz generiert. Cocoon extrahiert aus der obigen XSP-Datei eine compilierbare Java-Datei. Diese Java-Datei wird dann übersetzt und das Compilat als .class-File auf der Festplatte abgelegt. Das Java-Listing sieht wie folgt aus:
package _home._sm._cocoon._dokumente._demo; import java.io.*; import java.util.*; import org.w3c.dom.*; import org.xml.sax.*; import javax.servlet.*; import javax.servlet.http.*; import org.apache.cocoon.parser.*; import org.apache.cocoon.producer.*; import org.apache.cocoon.framework.*; import org.apache.cocoon.processor.xsp.*; import org.apache.cocoon.processor.xsp.library.*; /* User Imports */ import java.util.Date; import java.text.DateFormat; public class _notiz2 extends XSPPage { /* User Class Declarations */ public void populateDocument( HttpServletRequest request, HttpServletResponse response, Document document ) throws Exception { // Node stack logic variables Node xspParentNode = null; Node xspCurrentNode = document; Stack xspNodeStack = new Stack(); // Make session object readily available HttpSession session = request.getSession(true); document.appendChild( document.createProcessingInstruction( "cocoon-process", "type=\"xslt\"" ) ); document.appendChild( document.createProcessingInstruction( "xml-stylesheet", " href=\"notiz2html.xslt\" type=\"text/xsl\"" ) ); xspParentNode = xspCurrentNode; xspNodeStack.push(xspParentNode); xspCurrentNode = document.createElement("notiz"); xspParentNode.appendChild(xspCurrentNode); xspCurrentNode.appendChild( document.createTextNode("\n ") ); xspParentNode = xspCurrentNode; xspNodeStack.push(xspParentNode); xspCurrentNode = document.createElement("titel"); xspParentNode.appendChild(xspCurrentNode); xspCurrentNode.appendChild( document.createTextNode("Termine") ); ((Element) xspCurrentNode).normalize(); xspCurrentNode = (Node) xspNodeStack.pop(); xspCurrentNode.appendChild( document.createTextNode("\n ") ); xspParentNode = xspCurrentNode; xspNodeStack.push(xspParentNode); xspCurrentNode = document.createElement("autor"); xspParentNode.appendChild(xspCurrentNode); xspCurrentNode.appendChild( document.createTextNode("Weihnachtsmann") ); ((Element) xspCurrentNode).normalize(); xspCurrentNode = (Node) xspNodeStack.pop(); xspCurrentNode.appendChild( document.createTextNode("\n ") ); xspParentNode = xspCurrentNode; xspNodeStack.push(xspParentNode); xspCurrentNode = document.createElement("datum"); xspParentNode.appendChild(xspCurrentNode); xspCurrentNode.appendChild( document.createTextNode("24.12.2000") ); ((Element) xspCurrentNode).normalize(); xspCurrentNode = (Node) xspNodeStack.pop(); xspParentNode = xspCurrentNode; xspNodeStack.push(xspParentNode); xspCurrentNode = document.createElement("restzeit"); xspParentNode.appendChild(xspCurrentNode); Date jetzt = new Date(); DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT,Locale.GERMANY); String terminS = "24.12.2000"; Date termin = new Date(); termin = df.parse(terminS); long tage = (termin.getTime() - jetzt.getTime()) / 1000 / 60 / 60 / 24; xspCurrentNode.appendChild( xspExpr(tage, document) ); xspCurrentNode.appendChild( document.createTextNode(" Tagen") ); ((Element) xspCurrentNode).normalize(); xspCurrentNode = (Node) xspNodeStack.pop(); xspCurrentNode.appendChild( document.createTextNode("\n ") ); xspParentNode = xspCurrentNode; xspNodeStack.push(xspParentNode); xspCurrentNode = document.createElement("absatz"); xspParentNode.appendChild(xspCurrentNode); xspCurrentNode.appendChild( document.createTextNode("Nicht vergessen:\n ") ); xspParentNode = xspCurrentNode; xspNodeStack.push(xspParentNode); xspCurrentNode = document.createElement("wichtig"); xspParentNode.appendChild(xspCurrentNode); xspCurrentNode.appendChild( document.createTextNode("Geschenke austeilen") ); ((Element) xspCurrentNode).normalize(); xspCurrentNode = (Node) xspNodeStack.pop(); xspCurrentNode.appendChild( document.createTextNode("\n ") ); ((Element) xspCurrentNode).normalize(); xspCurrentNode = (Node) xspNodeStack.pop(); xspCurrentNode.appendChild( document.createTextNode("\n ") ); xspParentNode = xspCurrentNode; xspNodeStack.push(xspParentNode); xspCurrentNode = document.createElement("absatz"); xspParentNode.appendChild(xspCurrentNode); xspCurrentNode.appendChild( document.createTextNode(" ... ") ); ((Element) xspCurrentNode).normalize(); xspCurrentNode = (Node) xspNodeStack.pop(); xspCurrentNode.appendChild( document.createTextNode("\n") ); ((Element) xspCurrentNode).normalize(); xspCurrentNode = (Node) xspNodeStack.pop(); } }
Hieran ist abzulesen, dass nach und nach die neue Notiz-Instanz durch document.createElement() und document.createTextNode() zusammengebaut wird. An der entscheidenden Stelle werden die Java-Anweisungen aus der XSP-Seite ausgeführt und das Ergebnis in das neue Dokument eingefügt. Nach diesem Schritt 2 liegt wieder eine Notiz vor, die ein neues Element namens restzeit enthält; darin steht die berechnete Anzahl der Tage. Das jetzt arbeitende Stylesheet notiz2html.xslt transformiert in Schritt 3 die Daten abschließend in die nachfolgende HTML-Form. Die Browser-Darstellungen im Navigator und Explorer sind in Abbildung 70 und Abbildung 71 zu sehen.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><title>Notiz</title><style type="text/css"> <!-- body { text-align: center; background: #cccccc; } table { padding: 1ex; } div.framed { margin-left: 20%; margin-right: 20%; margin-top: 4ex; background: white; border: solid medium black; } span.titel { font-size: 200%; } .autor { color: #0000cc; font-weight: bold; } .datum { color: #00cc00; text-weight: bold; } .wichtig { color: white; background: red; } address { margin-top: 2ex; } --> </style></head><body><div class="framed"><table> <tr><th colspan="2"><span class="titel">Termine</span></th></tr> <tr><td align="right">von</td><td><span class="autor">Weihnachtsmann</span></td></tr> <tr><td align="right">für den</td><td><span class="datum">24.12.2000</span></td></tr><tr><td align="right">in</td><td><span class="restzeit">306 Tagen</span></td></tr> <tr><td></td><td><p class="absatz">Nicht vergessen: <span class="wichtig">Geschenke austeilen</span> </p></td></tr> <tr><td></td><td><p class="absatz"> ... </p></td></tr> </table></div><address> Copyright © 2000 <a href="http://www.mintert.com/">Stefan Mintert</a>.<br><a href="http://www.mintert.com/xml/">XML in der Praxis</a><br></address></body></html> <!-- This page was served in 636 milliseconds by Cocoon 1.6.1 -->