Webmaster brauchen Links. In vielen Fällen, wenn nicht den meisten, residieren diese Links in statischen HTML-Seiten, die oft mühevoll auf dem neuesten Stand gehalten werden müssen. Mit XML und XSLT können die geplagten Verwalter des Web sich die Arbeit erleichtern. Den Anfang dessen soll die folgende Anwendung zeigen.
Wer Linklisten zur Verfügung stellt, tut das
sicherlich überwiegend zu bestimmten Themen. XML
wiederum bietet die Möglichkeit, sich eigene Dokumenttypen zu
definieren, in denen Elemente und Attribute eine thematische
Zuordnung vornehmen. Aus XML-Instanzen wiederum
lassen sich über ein XSLT-Stylesheet beliebig
viele statische HTML-Dateien
erzeugenBeim derzeitgen Stand der Geschwindigkeit
von Java beziehungsweise Java-Programmen wie
XT oder Saxon kann man
Webmastern nicht dazu raten, diese Dokumente dynamisch zu
liefern..
Zur Anwendung selbst. Ziel war es, unterschiedliche
Produkte aus dem Web-Bereich online aufzulisten, in diesem
Fall beschränkt auf zwei: Content-Management-Systeme und
Application Server. Wollte man die Liste erweitern, wären
HTML/XML-Editoren,
Java-Entwicklungsumgebungen oder VRML-Werkzeuge
denkbare Ergänzungen. Die folgende Dokumenttyp-Definition
(DTD) berücksichtig die möglichen Erweiterungen
dadurch, dass das Attribut
catcat steht für Kategorie;
ganz im Sinne der XML-Maxime, dass
terseness
of minimal importance
sei. für die Produktgruppe
keine konkrete Werteliste enthält (die immerhin auch
erweiterbar wäre), sondern nur zwingend erforderlich
ist. Außerdem enthält das Element prodgroup ein
weiteres Attribut, das Basis für den Titel der
HTML-Seite und deren Überschrift ist.
Die Produkte selbst müssen (als Attribut) natürlich unbedingt einen URL enthalten, denn sonst wäre das Ganze ja keine Linkliste. Zwei weitere Attribute bezeichnen die Produktversion und ob es sich um kommerzielle, Open Source oder Shareware handelt. Optional lassen sich auch besondere Eigenschaften und eine Kontaktperson festhalten.
<!ELEMENT software ( prodgroup+ ) > <!ELEMENT prodgroup ( product+ ) > <!ATTLIST prodgroup cat CDATA #REQUIRED title CDATA #REQUIRED > <!ELEMENT product ( company, pname, features?, contact? ) > <!ATTLIST product url CDATA #REQUIRED version CDATA #REQUIRED status ( commercial | free | shareware ) "commercial" > <!ELEMENT company ( #PCDATA ) > <!ELEMENT pname ( #PCDATA ) > <!ELEMENT features ( feature+ ) > <!ELEMENT feature ( #PCDATA ) > <!ELEMENT contact ( #PCDATA ) > <!ATTLIST contact email CDATA #IMPLIED >
An dieser Kurz-DTD ist vielleicht schon zu erkennen, wie man sie, und damit die Anwendung, ausbauen könnte. Das Top-Level-Element könnte statt software ja auch linkliste heißen und an Elementen neben Softwareprodukten weitere beinhalten.
Ob die Daten in einem DBMS oder in einer
Datei vorliegen sollen, ist eine Frage des Geschmacks und der
Datenmenge. Gerade Listen, die eine recht einfache Struktur
haben, setzen nicht viel voraus, um sie in einem
DBMS zu organisieren. Wer etwa mit Linux
und MySQL oder Windows NT und
Access arbeiten will, benötigt dafür
wahrscheinlich/hoffentlich keinen
DatenbankadministratorDas setzt im Falle von MySQL
sicherlich das Engagement voraus, sich selbst als Adminstrator
zu betätigen oder verzweifelt nach einem kompetenten Freund zu
suchen.. Im vorliegenden Fall gehen wir von einer
Datei aus, die etwa so aussieht
Um keine Werbung zu
machen, haben wir als Beispielprodukte solche aus dem
Open-Source-Umfeld benutzt.:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?> <!DOCTYPE software SYSTEM "software.dtd"> <software> <prodgroup cat="cms" title="Content-Management-Systeme"> <product url="http://www.opencms.org/" version="k.A." status="free"> <company>Mindfact</company> <pname>OpenCms</pname> </product> <!-- weitere Content-Management-Systeme --> </prodgroup> <prodgroup cat="appsrv" title="Application Server"> <product url="http://www.enhydra.org/" version="3.0" status="free"> <company>[Lutris Technologies et al.]</company> <pname>Enhydra</pname> </product> <!-- weitere Application Server --> </prodgroup> <!-- weitere Produktgruppen --> </software>
Um die Informationen in Dateien zu bringen, die a) die Content-Management-Systeme und b) die Application Server beinhalten, müssen entweder zwei Stylesheets vorhanden sein, die jeweils eine der beide Dateien schreiben, oder eins, das beide erzeugt. Zumindest in der aktuellen Version 1.0 sieht die XSLT-Spezifikation nicht mehrere Ausgabedateien vor. Die schon erwähnte XSLT-Implementierung Saxon von Michael Kay hingegen tut genau das, indem sie das auch in der Spezifikation vorgesehene Element xsl:output in Gestalt von saxon:output um das Attribut file erweitert. Aus eben diesem Grund kommt es hier — und in weiteren Beispielen (siehe etwa das Kapitel 20) — zum Einsatz.
Ein weiterer Grund für den Einsatz von Saxon sind andere Ergänzungen, die das Programm bietet: in diesem Fall das saxon:assign-Element, das es ähnlich dem xsl:variable erlaubt, einer Variablen Werte zuzuweisen, die zum Beispiel innerhalb des Attributs file nutzbar sind. Für die Benutzung von Saxon (das gilt auch für andere Werkzeuge, die Erweiterungen des Standards bieten) ist es nötig, ihren Namensraum im Element xsl:stylesheet anzugeben:
xmlns:saxon="http://icl.com/saxon"
legt fest, dass unter saxon:... immer ein Element zu verstehen ist, das Saxon-spezifisch ist und nicht dem XSLT-Namensraum (xsl:...) entstammt. Außerdem legt
extension-element-prefixes="saxon"
fest, dass diese Zeichenkette das Präfix für die erweiternden Elemente ist. Und schon die ersten Zeilen des weiter unten vollständig abgedruckten Stylesheet-Listings deuten an, dass es hier auch darum geht, die Ausgabe in ein Verzeichnis zu dirigieren:
<xsl:variable name="dir">html</xsl:variable> <xsl:variable name="filesep" select="system-property('file.separator')" /> <xsl:variable name="currentgroup"/>
Diese Variablenzuweisungen (siehe auch den Abschnitt
10.4.5 und 10.4.6) sind die Vorbereitung dafür, die
Ausgabe in ein Verzeichnis namens html
zu lenken. Und
filesep zeigt die in Java angestrebte Portabilität, denn
ob vorwärts oder rückwarts gewandter Schrägstrich, das Stylesheet wird
betriebssystemkonform arbeiten.
In den Templates für den Wurzelknoten und das
Top-Level-Element software geschieht nichts, außer
dass die Templates für die Kindelemente aufgerufen
werden. Erst das Template für das Element prodgroup
enthält die zentralen Bestandteile des Stylesheets. Der Grund
dafür liegt darin, dass für jede Produktgruppe eine eigene
Datei erzeugt werden sollMüsste das Stylesheet für
jedes Produkt eine Datei generieren, wären entsprechende
Statements wie vor allem saxon:output im Element
product zu platzieren..
Einer der entscheidenden Punkte in dem Stylesheet, das
die Dateien produziert, ist der Aufruf
des Elements
saxon:output, das, wie angedeutet, über die
Möglichkeit verfügt, die Ausgabe in über Variable definierte
Dateien zu lenken. Die oben erwähnten Variablen dir
und filesep ergeben html/
, und
currentgroup repräsentiert das Attribut
cat (die Zeichenkette .html
folgt am
Schluss), sodass der Wert des Attributs file
entweder html/cms.html
oder html/appsrv.html
ist.
<saxon:output file="{$dir}{$filesep}{$currentgroup}.html" method="html" indent="yes" doctype-public="-//W3C//DTD HTML 4.0 Transitional" doctype-system="http://www.w3.org/TR/REC-html40"> ... <saxon:output>
docptype-public und doctype-system beziehungsweise ihre Werte bewirken, dass in der Zieldatei der Dokumenttyp in der richtigen Form steht:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional" "http://www.w3.org/TR/REC-html40">
Innerhalb des saxon:output-Elements steht genau das, was das Stylesheet ausgeben soll. Das fängt an mit Elementen wie html, head, body oder table, die ohne Namensraumbezeichner verwendet werden können, weil der HTML-Namensraum in xsl:stylesheet als einziger ohne einen solchen Zusatz deklariert wird. Vieles von dem, was im Element prodgroup steht, ist Beiwerk für die HTML-Seite: Verweis auf ein CSS-Stylesheet, Menüeinträge et cetera. Die ebenso entscheidende wie aussagelose Zeile in diesem Template ist:
<dl><xsl:apply-templates/></dl>
Sie stößt die weitere Stylesheet-Arbeit an. Und die
erledigen die Templates für die anderen Elemente. In denen ist
es vor allem das Template für product, das noch
etwas tut. Mittels eines xsl:if weist es den
einzelnen Produkten einen Farbtupfer zu, je nachdem ob es sich
um ein kommerzielles oder frei erhältliches handelt. Im Template für
den Produktnamen muss der URL eingebaut
,
das heißt dem Element a als
xsl:attribute zugewiesen werden.
Bleibt uns noch, das Listing insgesamt und natürlich einen Screenshot zu zeigen.
Abbildung 35: appsrv.html zeigt die Application Server mit der Zusatzinformation, ob sie kommerziell oder Open Source sind
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/REC-html40" xmlns:saxon="http://icl.com/saxon" extension-element-prefixes="saxon"> <!-- Parameter und Variable --> <xsl:variable name="dir">html</xsl:variable> <xsl:variable name="filesep" select="system-property('file.separator')" /> <xsl:variable name="currentgroup"/> <!-- ....................Root............... --> <xsl:template match="/"> <xsl:apply-templates/> </xsl:template> <!-- ............Element software........... --> <xsl:template match="/software"> <xsl:apply-templates/> </xsl:template> <!-- ............Element prodgroup.......... --> <xsl:template match="prodgroup"> <saxon:assign name="currentgroup"> <xsl:value-of select="@cat"/> </saxon:assign> <saxon:output file="{$dir}{$filesep}{$currentgroup}.html" method="html" indent="yes" doctype-public="-//W3C//DTD HTML 4.0 Transitional" doctype-system="http://www.w3.org/TR/REC-html40"> <html> <head> <meta name="author" content="Henning Behme" /> <link title="software" type="text/css" rel="stylesheet" href="sw.css"/> <title><xsl:value-of select="@title"/></title> </head> <body> <table align="left" width="100%" border="0" cellspacing="0" cellpadding="0"> <!-- erste Tabellenreihe --> <tr><td width="25%" valign="top" rowspan="2"> <p><a href="/ix/raven/"><img src="/ix/images/raven/raven.sm.gif" width="99" height="86" border="0" alt="theRaven"/></a> <br/><a href="/ix/"><img src="/icons/buttons/ix.gif" width="80" height="20" border="0" alt="iX"/></a> <br/><br/><a href="/ix/raven/Web"><span class="menu">Web@iX</span></a> <br/><br/><a href="appsrv.html"><span class="menu">AppServer</span></a> <br/><a href="cms.html"><span class="menu">CMS</span></a></p></td> <!-- rechte Tabellenteile --> <td><h1><xsl:value-of select="@title"/></h1></td></tr> <!-- zweite Tabellenreihe --> <tr><td> <p class="nocss">Ein Styleeshet-fähiger Browser würde sich gut machen ;-)<br/> A stylesheet-enabled browser would come in handy ;-)</p> <hr noshade="noshade" size="1"/> <p><img src="/ix/images/dots/1dred.gif" width="8" height="8" alt="commercial product"/> <img src="/ix/images/dots/1tr.gif" width="5" height="1" alt="space"/> <strong>kommerzielles Produkt - </strong> <img src="/ix/images/dots/1dgreen.gif" width="8" height="8" alt="open source"/> <img src="/ix/images/dots/1tr.gif" width="5" height="1" alt="space"/> <strong>Open Source</strong></p> <dl><xsl:apply-templates/></dl> <!-- ---------------------- foot -------------- --> <hr width="85%" noshade="noshade" size="1"/> <p>Last modification: March 11, 2000 by <a href="/ix/editors/hb.html">hb</a>. <br/>Complaints, suggestions to <a HREF="mailto:www@ix.heise.de"> <em>iX</em>'s webmaster</a></p> </td></tr> </table> </body> </html> </saxon:output> </xsl:template> <!-- ............Element product............... --> <xsl:template match="product"> <dt><xsl:if test="@status='commercial'"> <img src="/ix/images/dots/1dred.gif" width="8" height="8" alt="commercial product"/> <img src="/ix/images/dots/1tr.gif" width="5" height="1" alt="space"/> </xsl:if> <xsl:if test="@status='free'"> <img src="/ix/images/dots/1dgreen.gif" width="8" height="8" alt="open source"/> <img src="/ix/images/dots/1tr.gif" width="5" height="1" alt="space"/> </xsl:if> <xsl:if test="@status='shareware'"> <img src="/ix/images/dots/1blueish.gif" width="8" height="8" alt="shareware"/> <img src="/ix/images/dots/1tr.gif" width="5" height="1" alt="space"/> </xsl:if> <xsl:apply-templates select="pname"/> <xsl:text> [Version: </xsl:text> <xsl:value-of select="@version"/> <xsl:text>]</xsl:text> </dt> <dd><xsl:apply-templates select="company"/> <xsl:if test="features"> [besondere Eigenschaften: <xsl:apply-templates select="features"/>] </xsl:if> </dd> </xsl:template> <!-- ............Element pname............... --> <xsl:template match="pname"> <strong><a> <xsl:attribute name="href"> <xsl:text>http://</xsl:text> <xsl:value-of select="ancestor::product/@url"/> </xsl:attribute> <xsl:apply-templates/></a></strong> </xsl:template> <!-- .......Elemente features | company | feature --> <xsl:template match="features | company | feature"> <xsl:apply-templates/> </xsl:template> </xsl:stylesheet>