On the Fly

XSLT gilt für viele als Sprache, die nicht beim Client, sondern nur serverseitig einsetzbar ist. Das heißt keineswegs, dass XML-Quellen jede Nacht statisch in HTML gewandelt werden müssten. Man kann sie auch dynamisch ausliefern.

vorlesen Druckansicht 1 Kommentar lesen
Lesezeit: 11 Min.
Von
  • Henning Behme
Inhaltsverzeichnis

In den beiden ersten Teilen dieses Tutorials waren aus XML-Quellen erzeugte statische HTML-Seiten das Ergebnis, um das es ging. Mit Hilfe eines XSLT-Prozessors und diverser Stylesheets ließen sich diese Zieldokumente generieren. XML dynamisch in HTML zu wandeln und es an den Client zu schicken, erfordert hingegen ein bisschen Zeit für die On-the-fly-Wandlung auf dem Server.

Im Wesentlichen sind es zwei Produkte, die diese Funktion ohne größere Anschaffungskosten bieten: das Java-basierte Apache-Projekt Cocoon, das derzeit in der Version 1.8 vorliegt, und das von Matt Sergeant entwickelte Perl-Modul AxKit, momentan in Version 1.2. Beide sind kostenlos zu haben, was sich von anderen erhältlichen Application-Servern nicht sagen lässt.

Mehr Infos

Online-Ressourcen

AxKit ManualPage (auch über perldoc AxKit)

Matt Sergeant; AxKit: Web Publishing with Apache and mod_perl

XPathScript - A Viable Alternative to XSLT?
axkit.org/docs/xpathscript/guide.dkb ; auch
www.xml.com/pub/a/2000/07/05/xpathscript/index.html

Matt Sergeant; AxKit-Präsentation (ApacheCon 2000, London)

Rael Dornfest; AxKit: An XML-Delivery Toolkit for Apache

Kip Hampton; Creating Web Utilities Using XML::XPath

Zu Cocoon hat iX ansatzweise schon berichtet (siehe [1]); ein Artikel zur neueren Version ist geplant. Hier soll es um das ‘XML-Delivery Toolkit’ AxKit - wie Rael Dornfest es genannt hat - gehen, genauer, darum, wie mit Hilfe des Moduls Surfer XML-Daten aufrufen (beispielsweise xml.ix.heise.de/ix/cebit01/xslt/brief/brief1.xml) und auf ihrem Browser HTML landet. Damit das geschehen kann, muss natürlich AxKit erst einmal in die lokale Perl-Hierarchie des Webservers eingebunden sein. Perl-Kennern ist der Vorgang vertraut:

perl Makefile.PL
make
make test
make install

Für den letzten Schritt sind Root-Rechte erforderlich, damit der Schreibzugriff auf /usr/lib/perl5 oder ähnlich gelagerte Verzeichnisse möglich ist. Welche Komplikationen sich bei und nach der Installation von AxKit ergaben und wie dessen Konfiguration im Apache aussieht, ist im ‘Labor-Alltag’ nachzulesen. Eine erfolgreiche Installation vorausgesetzt, steht als Nächstes an, die Apache-Konfiguration zu erweitern, denn AxKit arbeitet über mod_perl direkt mit dem Apache zusammen. Innerhalb dessen httpd.conf kann die Webmistress ein oder mehrere Cache-Verzeichnisse anlegen, den Ausgabezeichensatz festlegen (wenn es nicht UTF-8 sein soll) und für unterschiedliche Dateien und Verzeichnisse weitere Optionen setzen. Listing 1 zeigt einen solchen Eintrag in httpd.conf, der für das Dokumentenverzeichnis /xslt AxKit als aktiv setzt, die Ausgabe als ISO-Latin1 festschreibt, einen Cache vorsieht und für zwei unterschiedliche Dateitypen Perl-Module aktiviert.

Mehr Infos

Listing 1: AxKit-Konfiguration

#
# in httpd.conf
#
PerlModule AxKit

#
# entweder in httpd.conf (wie hier) oder
# in einer .htaccess-Datei
#

<Location /xslt>
SetHandler perl-script
PerlHandler AxKit
PerlSetVar AxTranslateOutput 1
PerlSetVar AxOutputCharset ISO_8859-1
AxCacheDir /home/httpd/htdocs/axkit_cache
AxAddStyleMap application/x-xpathscript Apache::AxKit::Language::XPathScript
AxAddStyleMap text/xsl Apache::AxKit::Language::Sablot
</Location>

Für die reine XSLT-Verarbeitung ist der Typ text/xsl zuständig, und das Teil-Modul Sablot verarbeitet die XML-Quelle. application/x-xpathscript steht für die von Sergeant entwickelte Skriptsprache XPathScript und benennt das gleichnamige Modul als Handler. Aber zunächst soll es um XSLT pur gehen.

Um das erste Beispiel aus Teil I aufzugreifen: ein in XML geschriebener Brief wie Listing 2 unterscheidet sich im Wesentlichen durch die zweite Zeile vom Beispiel in Teil I des Tutorials; sie verweist - innerhalb des XML-Dokuments - auf ein Stylesheet, das die Transformation in HTML beim Aufruf des Dokuments vornimmt. Aufzurufen ist der Brief mit

http://xml.ix.heise.de/ix/cebit01/xslt/brief/brief2.xml

Den oben stehenden Brief wandelt AxKit in HTML; die Darstellung gibt ein Cascading Stylesheet vor (Abb. 1).

(auch der erste Brief befindet sich dort). Auf Serverseite, eben durch die zweite Zeile des Dokuments, entscheidet der httpd, die Verarbeitung an AxKit weiterzureichen, das an Hand des Typs text/xsl Sablot einschaltet. brief.xsl liefert die Informationen für die Transformation, und Abbildung 1 zeigt das Ergebnis der Wandlung im Browser.

Mehr Infos

Listing 2: brief2.xml

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>

<?xml-stylesheet href="brief2.xsl" type="text/xsl"?>

<!DOCTYPE brief SYSTEM "brief.dtd">

<brief>

<anrede geschlecht="m" sozial="sie">Joyce</anrede>

<text>soeben haben wir den Ulysses bis zum Ende
gelesen. Vorausgesetzt, Sie wŠren bereit, das letzte
Kapitel zu Ÿberarbeiten oder gŠnzlich zu streichen,
wŠren wir einer Veršffentlichung nicht
abgeneigt.</text>

<gruss form="hoch">John J. Hoover</gruss>

</brief>

Das Stylesheet enthält nichts anderes als das im ersten Teil des Tutorials; bis auf die Tatsache, dass hier der Gruß noch ein Attribut enthält, das den Grad der Vertrautheit signalisiert:

<!ATTLIST gruss
form (hoch|mittel|niedrig) #REQUIRED >

Je nach Attributwert enthält der Gruß eine Formel.

Dokumente wie dieses, auch wenn sie umfangreicher sind, eignen sich gut fürs Caching, weil sie sich nicht häufig ändern. Anders ist das beim ebenfalls in Teil I verwendeten Wörterbuch: hier kann ständig ein neuer Eintrag vorgenommen worden sein. Hinsichtlich solcher XML-Quellen sind bei Benutzung von AxKit mehrere ‘Dinge’ zu bedenken.

AxKit wirft keinen Blick in die zum Dokument gehörende DTD. Das bedeutet unter anderem, dass so genannte Default-Werte, die die DTD vorgibt, für AxKit unbekannt sind. Im Rahmen des Wörterbuchs heißt dass: Für jedes Element expl ist die Sprache explizit anzugeben; es reicht nicht, sie nur im Falle des Englischen ausdrücklich einzutragen, weil Deutsch als Default notiert ist <expl lang=’de’>...</expl>.

Und im Zusammenhang mit der Ausgabe einzelner Einträge stellte sich heraus, dass AxKits Cache jedes Dokument speichert, aber auf der Basis des gesamten Dokuments, nicht unter Berücksichtigung ihm übergebener Parameter. Identisch auf Cache-Ebene (und nur dort) wären demnach

dictionary.xml
dictionary.xml?myentry=css
dictionary.xml?myentry=xml

Das darf nicht sein. Aber dafür ist AxKit zu modifizieren, was hier nicht weiter behandelt wird (der Hausperlianer wirds richten). Vielmehr soll es darum gehen, wie sowohl das Inhaltsverzeichnis als auch die Einzeldaten zum Surfer kommen.

Statt viele statische HTML-Dateien zu erzeugen, reicht es für AxKit, das Wörterbuch wie gehabt in einer Datei vorzuhalten und - analog zum Brief oben - ein Stylesheet zu referenzieren, das dafür sorgt, was wie ausgegeben wird. Listing 3 enthält den Anfang der XML-Quelle, Listing 4 den des Stylesheet.

Mehr Infos

Listing 3: dictionary.xml

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>

<?xml-stylesheet href="dictionary.xsl" type="text/xsl"?>

<!DOCTYPE dictionary SYSTEM "dictionary.dtd">

<dictionary>

<!-- Eintraege -->

</dictionary>
Mehr Infos

Listing 4: dictionary.xsl

<?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">

<xsl:output method="html"/>

<xsl:param name="myentry"/>

<!-- ............root.................. -->
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$myentry=''">
<xsl:apply-templates select="dictionary"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="//entry[@id=$myentry]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<!-- weitere Templates -->

</xsl:stylesheet>

Für dictionary.xml gilt dasselbe wie für den Brief: die einzige Veränderung ist der Verweis aufs Stylesheet, hier dictionary.xsl. Die DTD anzugeben ist für AxKit (siehe oben) nicht erforderlich. Im Stylesheet selbst ist die Ausgabe xsl:output auf HTML gesetzt. Hier darf das Attribut encoding nicht stehen, sonst gibts UTF-8 statt ISO-Latin1 im Browser.

<xsl:param name="myentry"/>

dient dazu, dem Dokument auf dem üblichen Wege einen Parameter übergeben zu können, was die Anzeige einzelner Einträge ermöglicht. Der Parameter ist nur definiert, hat also keinen Wert. Das ist im Root-Template von Bedeutung, denn hier entscheidet sich (beziehungsweise das Stylesheet), ob über das Template für dictionary ein Inhaltsverzeichnis oder über select=’//entry[@id=$myentry]’ der Eintrag mit der übergebenen ID an den Browser geht. Ein Aufruf von

http://xml.ix.heise.de/ix/cebit01/xslt/dict/dictionary.xml

heißt, dass myentry keinen Wert hat und das Stylesheet deshalb in das Template dictionary verzweigt. Dort kommt es zur Ausgabe der Übersicht, die Abbildung 2 zeigt; das Template ist Listing 5 zu entnehmen. Die entscheidende Zeile dort ist

<xsl:apply-templates select="//acro" mode="toc"/>
Mehr Infos

Listing 5: Inhaltsverzeichnis

<!-- ............dictionary entry (toc).................. -->
<xsl:template match="dictionary">
<html>
<head>
<meta name="author" content="Henning Behme" />
<meta name="keywords" content="iX Web dictionary iX-Woerterbuch" />
<title>iX Web dictionary</title>
<link rel="stylesheet" href="dictionary.css" type="text/css"/>
</head>
<body>
<table border="0" width="100%" cellspacing="0" cellpadding="5">
<tr><td rowspan="4" valign="top" width="30%">
<img src="/ix/images/iX.mini.tr.gif" alt="iX logo"/></td>
<td><h1>Web Dictionary</h1></td>
</tr>
<tr><td><img src="/ix/images/dots/1lblue.gif" alt="line"
width="100%" height="1"/></td>
</tr>
<tr><td><p><xsl:apply-templates select="//acro" mode="toc"/></p></td>
</tr>

<tr><td><xsl:call-template name="do-foot"/></td></tr>
</table>
</body>
</html>
</xsl:template>

Wie das Inhaltsverzeichnis zu erstellen ist, zeigt Listing 5. Das Ergebnis enthält Links zu den einzelnen Einträgen, die im nicht sichtbaren Template für acro mit dem Modus toc erzeugt werden (Abb. 2).

Sie bewirkt, dass ausgehend vom Element dictionary alle an beliebiger Stelle im Dokument vorkommenden Begriffe (//acro) ausgegeben werden, im Modus des Inhaltsverzeichnisses (mode="toc").

Ist myentry nicht leer, gilt xsl:otherwise in der Abfrage des Root-Template (Listing 4) und der XSLT-Prozessor liefert die Daten zum dazugehörenden Eintrag. Im Falle von myentry=xslt sieht das Ergebnis aus wie Abbildung 3. Hierzu durchsucht das Stylesheet mit

select="//entry[@id=$myentry]"

alle im Dokument vorhandenen Einträge darauf, ob sie die ID $myentry haben. Nur wenn beide übereinstimmen, wird der Eintrag ausgeliefert. Und da eine ID im Dokument eindeutig sein muss, ist gewährleistet, dass jeweils nur ein Begriff der richtige ist.

Für jeden einzelnen Eintrag wird am linken Rand auch ein Inhaltsverzeichnis erzeugt. Rechts daneben sind jeweils die Details hinsichtlich eines konkreten Begriffs zu sehen (Abb. 3).

Anmerkung: Anders als in den beiden ersten Teilen sind die Stylesheets in diesem nicht aufgeteilt, sondern alle Templates befinden sich in einem einzigen Dokument. Grund dafür ist, dass der in diesem Fall verwendete XSLT-Prozessor Sablot(ron), der momentan in Version 0.50 vorliegt, xsl:include noch nicht kennt.

So weit XSLT. Denn Sergeant hat seinem AxKit mit XPathScript etwas beigegeben, das mit den eigentlichen XSL-Transformationen nichts zu tun hat, außer das die Skriptsprache XML-Dokumente ebenfalls bearbeitet. Vor allem der berühmte DPH (Desperate Perl Hacker) dürfte sich darauf und darüber freuen. Das in

Apache::AxKit::Language::XPathScript

realisierte Modul erlaubt es, XML-Quellen über eine Stylesheet-Anweisung an ein Skript zu binden. Dies wiederum erzeugt aus HTML-Code und in ASP-Manier (<% ... %>) eingeschlossene Perl-Zeilen das Zieldokument. Skriptdateien haben die Endung .xps und sind vom Typ application/x-xpathscript. Was es mit solchen Dateien auf sich hat, muss der Webmaster in der Apache-Konfigurationsdatei httpd.conf hinterlegen. Listing 1 enthält eine Zeile, die dem Apache mitteilt, was er mit dem genannten Typ anzufangen hat:

AxAddStyleMap application/x-xpathscript \
Apache::AxKit::Language::XPathScript

teilt dem Webserver mit, dass Dateien vom Typ application/x-xpathscript vom AxKit-Modul XPathScript zu bearbeiten sind.

Für eine intensive Darstellung fehlt hier natürlich der Platz, aber zwei Beispiele sollen den prinzipiellen Umgang mit der Skriptsprache zeigen. XML-Grundlage ist schon wieder das oben benutzte Wörterbuch, das nun am Anfang ein anderes Stylesheet referenziert:

<?xml-stylesheet 
href="dictionary.xps"
type="application/x-xpathscript"?>

Unterschiede in beiden Attributen: auf Grund der Skriptsprache bekommt das Stylesheet die Endung .xps, und der Typ darf aus oben genanntem Grund nicht text/xsl sein. Als Erstes und ganz am Schluss zeigt die XPathSkriptdatei (Listing 6) die einfachen HTML-Sequenzen, die den Anfang des Dokuments bilden sollen. Dazwischen befindet sich der Perl-Code, der die Ausgabe bestimmt.

Mehr Infos

Listing 6: XPathScript 1

<html>
<head>
<title>iX Dictionary</title>
<link rel="stylesheet" type="text/css"
href="dictionary.css">
</head>
<body>

<h2 align="center">iX Dictionary:
XPathScript-Beispiel 1</h2>

<table align="center" width="80%"
cellspacing="0" cellpadding="1">

<%
foreach my $entry (findnodes("/dictionary/entry")) {
print "<tr>";
print "<td align=\"right\"><strong>",
$entry->findvalue("acro/text()"),
"</strong></td>";
print "<td>",
$entry->findvalue("term/text()"),
"</td>";
print "</tr>\n";
}
%>

</table>
</body>
</html>

Zunächst belegt das Skript die Variable $entry mit dem Ergebnis von

(findnodes("/dictionary/entry"))

Für jeden Eintrag (jedes Element entry) enthält der foreach-Block ein paar print-Anweisungen, die hier nur der Übersichtlichkeit halber so getrennt sind; andere Schreibweisen sind möglich.

Nachdem findnodes() die Einträge gefunden hat, kann die Methode findvalue() von $entry die innerhalb des gefundenen Nodeset vorhandenen Elemente/Knoten acro und term aufsuchen und ihren Textinhalt ausgeben.

Mehr Infos

Listing 7: XPathScript 2

<%

$t->{'acro'}{pre} = '<tr><td align="right"><strong>';
$t->{'acro'}{post} = '</strong></td>';

$t->{'term'}{pre} = '<td align="left">';
$t->{'term'}{post} = '</td></tr>';

%>

<!-- Alternative zum folgenden print:
<%= apply_templates("/dictionary/entry/acro | ...") %>
-->

<%
print apply_templates("/dictionary/entry/acro
| /dictionary/entry/term")
%>

Die Möglichkeiten von XPathScript gehen allerdings über solche einfachen print-Folgen hinaus. Das ‘Durcheinander’ von HTML und XPathScript in Listing 6 lässt sich beispielsweise vermeiden, wie in Listing 7 nachzulesen ist. Denn XPathScript kennt den Hash $t, der als Schlüssel ein im XML-Dokument vorkommendes Element erwartet, als Subschlüssel einen der im Kasten ‘Unterschlüssel’ aufgelisteten haben kann und im jeweils letzten Feld meist das Auszugebende enthält. Statements wie

$t->{'acro'}{pre} = '<strong>';
$t->{'acro'}{post} = '</strong>';

Aus dem Wörterbuch extrahieren Listing 6 und Listing 7 auf unterschiedliche Weise eine Liste der Akronyme und ihrer Bedeutung; die Verlinkung ist hier unberücksichtigt (Abb. 4).

legen für das Elementacro fest, dass bei seinem Auftreten vor ihm der Start-Tag <strong> und nach ihm der End-Tag </strong> stehen soll. Wie Sergeant auf seine eigenen Artikel, die er mit DocBook erstellt, bezogen schreibt, lassen sich auf diese Weise für ganze Dokumente Vorgaben machen, wie die einzelnen Elemente zu verarbeiten sind. Da passt es gut, dass in XPathScript ein Teil der Server-side Includes (SSI) implementiert ist: das Einbinden von Dateien (mehr derzeit nicht).

Hat man also für bestimmte Dokumente viele solcher Anweisungen geschrieben, kann man sie durch

<!-#include file="fewtags.xps"->

einbeziehen. - Was fehlt, sind komplexere Anwendungen. Sergeant gibt in seinem Guide ‘XPathScript - A Viable Alternative to XSLT?’ (siehe ‘Online-Ressourcen’) ein paar Beispiele, der Rest ergibt sich für Perlianer wahrscheinlich von selbst ...

[1] Stefan Mintert; Web-Programmierung; Serving XML; XML-Daten ins WWW liefern; iX 10/1999, S. 178

Mehr Infos

iX-TRACT

  • AxKit ist ein Perl-Modul, das sich in den Apache integriert und es erlaubt, XML dynamisch als HTML an Browser auszuliefern.
  • XML-Quellen müssen für die Ausgabe mit AxKit einen Verweis auf ein XSLT-Stylesheet beinhalten. Parameter können die Ausgabe beeinflussen.
  • Über reine XSLT-Verarbeitung hinaus beinhaltet AxKit die Skriptsprache XPathScript, mit der Entwickler die Ausgabe programmieren können.
Unterschlüssel
XPathScript ‘kennt’ einen Hash namens $t, der es über Schlüssel, Subschlüssel und ein weiteres Feld erlaubt, Verarbeitungsschritte an zentraler Stelle vorzunehmen. Notation: $t{element}{subkey} = ‘...’;. element bezeichnet eins der in der XML-Quelle vorkommenden Elemente (und nur dies; nicht etwa als XPath-Ausdruck).
Unterschlüssel Inhalt
pre/post Ausgabe vor/nach dem Element
prechildren/postchildren Ausgabe vor/nach den Kindelementen des gegenwärtigen
prechild/postchild Ausgabe vor/nach den einzelnen Kindelementen des gegenwärtigen
showtag wenn wahr: Ausgabe des Start- und End-Tags des gegenwärtigen Elements; sonst nichts
testcode Code für die Bearbeitung des gegenwärtigen Elements

(hb)