• +49-(0)721-402485-12
Ihre Experten für XML, XQuery und XML-Datenbanken

Web Publishing Frameworks

In diesem Kapitel beginnt die Darstellung spezifischer Java- und XML-Themen. Bisher wurden die Grundlagen für die Benutzung von XML unter Java vorgestellt, ein Blick auf die SAX-, DOM-, JDOM- und JAXP-APIs zur Manipulation von XML geworfen und schließlich die Grundlagen der Benutzung und Erzeugung von XML selbst diskutiert. Nachdem Sie jetzt wissen, wie Sie XML von Ihrem Code aus benutzen können, wenden wir uns jetzt spezifischen Applikationen zu.

Die nächsten sechs Kapitel beschäftigen sich mit den wichtigsten Anwendungen von XML und speziell damit, wie diese Anwendungen im Java-Umfeld implementiert sind. Während es natürlich Tausende von wichtigen Anwendungen von XML gibt, sind die in den folgenden Kapiteln vorgestellten solche, die durch ihr Potential, die Herangehensweise an Entwicklungsprozesse drastisch zu ändern, ständig im Blickpunkt stehen.

Die erste heiße Sache, der wir uns zuwenden werden, ist die XML-Anwendung, die die meiste Begeisterung in der XML- und Java-Gemeinde ausgelöst hat: die Web Publishing Frameworks. Ich habe ständig betont, daß die Möglichkeit, die Präsentation aus dem Inhalt zu erzeugen, zu Ungunsten des Wertes der portablen Darstellung, die XML zur Verfügung stellt, überbewertet wird. Die Benutzung von XML zur Präsentation ist jedoch nach wie vor sehr wichtig. Diese Wichtigkeit erhöht sich noch mit Blick auf Web-Anwendungen.

Fast jede größere Anwendung, die man heutzutage sieht, ist entweder vollständig webbasiert oder hat wenigstens ein Web-Frontend. Die Benutzer verlangen mehr Funktionalität, die Marketingabteilungen mehr Flexibilität im Look-and-Feel. Das Resultat ist die Herausbildung des Web-Designers; dieses neue Berufsbild unterscheidet sich dahingehend vom Webmaster, daß das Programmieren in Perl, ASP, JavaScript oder anderen Skriptsprachen nur ein verschwindend kleiner Teil des Jobs ist. Der Tag eines Web-Designers ist ausgefüllt mit der Entwicklung, Erstellung und Modifikation von HTML- und WML-Dokumenten.1

Die schnellen Änderungen in der Geschäfts- und Marktstrategie können es unter Umständen einmal wöchentlich nötig machen, eine komplette Anwendung oder Webseite zu restrukturieren. Das bedeutet oft, daß der Web-Designer Tage damit zubringt, Hunderte HTML-Seiten zu ändern. Obwohl Cascading Style Sheets (CSS) hier eine Erleichterung brachten, benötigt man viel Zeit, um die Konsistenz all dieser Seiten sicherzustellen. Auch wenn diese nicht optimale Situation akzeptabel wäre, möchte doch kein Entwickler sein Leben mit dem Ändern von Webseiten zubringen.

Durch die Einführung von serverseitigem Java ist das Problem noch größer geworden. Entwickler von Servlets bringen viele Stunden mit nichts anderem zu als dem Umschreiben ihrer System.out.println( )-Anweisungen zur Ausgabe von HTML und schielen oft haßerfüllt auf die Marketingabteilung, wenn Änderungen am Aussehen einer Seite Anpassungen im Code nötig machen. Die Spezifikation der Java Server Pages (JSP) war das Resultat dieser Situation; jedoch sind auch JSP keine Lösung. Hier wird die Frustration lediglich auf den Autor des Inhaltes der Seiten verlagert, der ständig vor unbeabsichtigten Änderungen des benutzten Java-Codes auf der Hut sein muß. Außerdem stellen JSP nicht wirklich die versprochene klare Trennung zwischen Inhalt und Präsentation dar. Eine Möglichkeit, reinen Inhalt zu generieren, wird gebraucht, wie auch eine Möglichkeit, diesen Inhalt einheitlich sowohl zu festen Zeiten (static content generation) als auch dynamisch zur Laufzeit (dynamic content generation) zu formatieren.

Natürlich werden Sie bei der Schilderung dieses Problems mit dem Kopf nicken, wenn Sie bereits für das Web entwickelt haben, und hoffentlich wandern Ihre Gedanken in Richtung der Techniken XSL und XSLT. Das Problem ist aber, eine Engine zur Verfügung zu haben, die die Generierung der Inhalte übernehmen kann, speziell die dynamische. Hunderte XML-Dokumente auf einer Site zu haben bringt gar nichts, wenn keine Mechanismen da sind, mittels derer man auf eine Anforderung hin Transformationen ausführen kann. Fügt man dazu noch den Bedarf an Servlets und anderen serverseitigen Komponenten zur Ausgabe von konsistent formatierten XML-Dokumenten hinzu, hat man bereits einen Teil der Anforderungen an Web Publishing Frameworks definiert.

In diesem Kapitel wird ein Blick auf ein solches Framework geworfen – und darauf, wie man damit die vielen Stunden des Editierens von HTML-Dokumenten vermeidet. Es zeigt auch, wie man all diese Web-Designer in XML- und XSL-Gurus verwandeln kann, und wie das Framework es erlaubt, das Look-and-Feel von Anwendungen so oft zu ändern, wie es nötig erscheint.

Ein Web Publishing Framework versucht diese komplizierten Fragestellungen anzugehen. Genau wie ein Webserver dafür verantwortlich ist, auf einen URL-Request hin eine bestimmte Datei auszuliefern, reagiert auch ein Web Publishing Framework auf einen ähnlichen Request; jedoch wird hier nicht mittels einer Datei geantwortet, sondern mit einer publizierten Version einer Datei.

Hier bezieht sich der Begriff »publizierte Datei« auf eine Datei, die mittels XSLT transformiert, auf Anwendungsebene umformatiert oder in ein anderes Format, wie zum Beispiel PDF, konvertiert wurde. Derjenige, der den Request gestellt hat, wird nie die rohen Daten sehen, die dem publizierten Resultat zugrundeliegen, hat jedoch auch nicht ausdrücklich das Publizieren anzufordern. Oft kann man am Stamm eines URI (zum Beispiel http://yourHost.com/publish) erkennen, ob eine auf dem Web-Server aufsetzende Publishing-Engine (publishing: engl. für publizieren) eingehende Requests beantworten soll. Wie man vermuten könnte, ist das zugrundeliegende Konzept sehr viel einfacher als die eigentliche Implementierung eines solchen Frameworks – das ideale Framework für einen bestimmten Anwendungsfall zu finden ist keine einfache Aufgabe.

Ein Framework auswählen

Man könnte erwarten, eine Liste mit Hunderten möglicher Lösungen zu finden. Wie Sie gesehen haben, bietet Java eine einfache Schnittstelle zu XML über mehrere APIs. Zusätzlich offerieren Servlets einen eleganten und einfachen Weg, Web-Requests zu bearbeiten und die Antworten zu generieren. Die Liste von Frameworks ist trotzdem nicht lang, und die Liste der guten und stabilen Frameworks ist nochmals kürzer. Die beste Informationsquelle, um sich einen Überblick über die verfügbaren Produkte zu verschaffen, ist die Liste bei http://xmlsoftware.com/publishing/. Diese Liste ändert sich so oft, daß es sinnlos erscheint, ihren Inhalt hier widerzugeben. Einige Kriterien zur richtigen Auswahl eines bestimmten Frameworks sollen jedoch hier genannt werden.

Sie sollten nicht überrascht sein, daß es (immer noch!) schwierig ist, ein Produkt mit einer Versionsnummer größer als 2.x zu finden. Tatsächlich ist es so, daß man schon gründlich suchen muß, wenn man ein Framework finden will, das schon der zweiten Generation angehört. Obwohl eine höhere Versionsnummer nicht unbedingt ein Indikator für tatsächlich höhere Stabilität ist, gibt sie doch oft die Menge an Zeit, Aufwand und Tests wider, die in die Entwicklung des Frameworks eingeflossen ist. Das XML-Publishing-System ist so neu, daß der Markt durch Produkte mit den Versionsnummern 1.0 und 1.1 überschwemmt ist, die einfach nicht stabil genug für eine ernsthafte Anwendung sind.

Sie können oft auf die Stabilität eines bestimmten Produktes schließen, wenn man andere Produkte desselben Herstellers vergleicht. Es kommt oft vor, daß ein Hersteller gleich eine ganze Sammlung von Tools veröffentlicht; wenn diese Tools keine Unterstützung für SAX 2.0 und DOM Level 2 bieten oder als Versionen 1.0 oder 1.1 vorliegen, sollte man die Finger so lange vom entsprechenden Framework lassen, bis es ausgereifter ist und neuere XML-Standards unterstützt. Sie sollten versuchen, sich von plattformspezifischen Lösungen fernzuhalten. Wenn ein Framework an eine bestimmte Plattform (wie zum Beispiel Windows oder spezielle Unix-Varianten) gebunden ist, arbeitet man nicht mit einer reinen Java-Lösung. Sie sollten bedenken, daß ein solches Framework Clients auf beliebigen Plattformen bedienen können muß. Warum sollten Sie also eines benutzen, das nicht auf allen Plattformen lauffähig ist?

Wenn Sie wissen, daß das gewählte Framework stabil genug für das Einsatzszenario ist, sollten Sie sicherstellen, daß es eine Vielzahl von XML-Parsern und Prozessoren unterstützt. Ist es auf einen speziellen Parser oder Prozessor angewiesen, sind Sie auf eine bestimmte Implementierung einer Technologie festgelegt. Das ist schlecht. Wenngleich Frameworks oft mit einem speziellen Parser besonders gut zusammenarbeiten, sollten Sie überprüfen, ob der Parser einfach austauschbar ist. Haben Sie einen Lieblingsprozessor (zum Beispiel aus einem früheren Projekt), sollten Sie sicherstellen, daß er benutzt werden kann.

Die Unterstützung von SAX und DOM muß vorhanden sein. Viele Frameworks unterstützen JDOM und JAXP inzwischen ebenfalls. Selbst wenn Sie eine Lieblings-API haben – je mehr Optionen, desto besser! Es ist ebenfalls nützlich, wenn die Entwickler des benutzten Frameworks die Spezifikationen von XML, Schema, XLink, XPointer und anderen neuen XML-Technologien verfolgen. Das gibt schon einen Anhaltspunkt dafür, ob zukünftige Versionen des Frameworks diese XML-Spezifikationen unterstützen werden: ein wichtiger Hinweis auf die Langlebigkeit des Frameworks. Sie sollten nicht davor zurückschrecken, nach dem Zeitpunkt der Integration neuer Technologien zu fragen, und auf einer definitiven Antwort bestehen.

Die letzte und vielleicht wichtigste Frage, die auf der Suche nach einem passenden Web Publishing Framework beantwortet werden muß, ist die, ob das Framework in anderen Anwendungen benutzt wird. Finden Sie keine Referenzen auf wenigstens ein paar Anwendungen oder Sites, die das Framework nutzen, sollten Sie nicht überrascht sein, wenn es keine gibt. Händler (bzw. Entwickler in der Open Source-Bewegung) sollten glücklich und stolz darauf sein, Quellen angeben zu können, wo man ihr Framework in Aktion sehen kann. Hält man sich hier bedeckt, ist das ein Zeichen, daß Sie wahrscheinlich in der Benutzung des Frameworks mehr Pionierarbeit leisten müssen, als Sie eigentlich beabsichtigten. Apache Cocoon zum Beispiel pflegt eine solche Liste mit Referenzen online unter https://cocoon.apache.org/live_sites_3.0.html.

Haben Sie diese Kriterien geprüft, haben Sie sehr wahrscheinlich die Antwort schon deutlich vor Augen. Nur sehr wenige Frameworks entsprechen in allen hier aufgeführten Punkten den genannten Anforderungen, ganz zu schweigen von den Anforderungen, die die konkrete Anwendung stellt. Tatsächlich existierten im Juli 2001 weniger als zehn Publishing Frameworks, die die aktuellen Versionen von SAX (Version 2.0), DOM (Level 2) und JAXP (Version 1.1) unterstützen, auf wenigstens einer Site benutzt werden und wenigstens auf drei wichtige Versionen zurückblicken können. Sie sind hier nicht aufgeführt, da sie schon nach einem halben Jahr nicht mehr existieren oder zumindest radikal geändert worden sein könnten. Die Welt der Web Publishing Frameworks ist dermaßen im Fluß, daß die Nennung von vier oder fünf Optionen unter Annahme, daß sie in vier oder fünf Monaten noch existieren, Sie mehr in die Irre führen als Ihnen helfen würde.

Trotzdem gibt es ein Web Publishing Framework, das innerhalb der Java- und XML-Gemeinde durchgängig erfolgreich war. Besonders wenn man die Open Source-Gemeinde betrachtet, wird dieses Framework oft von Entwicklern gewählt. Das von Stefano Mazzochi gegründete Apache Cocoon-Projekt war vom Start weg ein stabiles Framework. Entwickelt in einer Zeit, als die meisten noch herauszufinden versuchten, was XML eigentlich ist, geht Cocoon nun in die zweite Generation als komplett in Java implementiertes XML-Publishing Framework. Es ist Teil des Apache-XML-Projekts und bietet standardmäßig Unterstützung für Apache Xerces und Apache Xalan. Es gestattet, jeden XML-konformen Parser zu benutzen, und baut auf der immens populären Servlet-Architektur auf. Außerdem gibt es einige Sites, die Cocoon (in einer 1.x-Version) benutzen und dadurch die Beschränkungen des traditionellen Web-Designs aufweichen. Dennoch arbeiten diese Sites sehr gut. Aus diesem Grund und um den Geist von Open Source zu unterstützen, wird Apache Cocoon in diesem Kapitel als Framework der Wahl benutzt.

In den vorangegangenen Kapiteln wurde die Wahl von XML-Parser und -Prozessor nicht eingeschränkt. Das heißt, daß die Beispiele auf verschiedenen Implementierungen mit nur kleinen Änderungen im Code lauffähig sein sollten. Web Publishing Frameworks sind jedoch nicht standardisiert, und so implementiert jedes Framework wild irgendwelche verschiedenen Features und Konventionen. Aus diesem Grund sind die in diesem Kapitel vorgestellten Beispiele nicht portabel, die Popularität der in Cocoon benutzten Design Patterns und Konzepte rechtfertigt jedoch ein eigenes Kapitel. Auch wenn Sie Cocoon nicht benutzen möchten, sollten Sie dennoch einen Blick auf die Beispiele werfen. Die Konzepte des Web-Publishing sind in jeder Implementierung wiederzufinden, auch wenn man den Code nicht wiederverwenden kann.

Installation

In den anderen Kapiteln beschränkten sich irgendwelche Installationsanweisungen auf die Angabe einer Website, von der Sie eine Distribution der entsprechenden Software herunterladen konnten, und auf das Hinzufügen der entsprechenden jar-Datei zum Klassenpfad. Die Installation eines Frameworks wie Cocoon ist nicht ganz so einfach; die benötigten Prozeduren werden hier erklärt. Zusätzlich dazu bietet Cocoon online weitere Dokumentationen für andere Servlet-Engines unter http://xml.apache.org/cocoon/install.html.

Zunächst müssen Sie entscheiden, ob Sie lieber den Sourcecode oder die Binaries verwenden möchten. Diese Entscheidung können Sie auch davon abhängig machen, ob Sie die neuesten Features benutzen möchten oder den verläßlichsten Build. Für Hardcore-Entwickler, die richtig in Cocoon eintauchen wollen, ist es besser, eine Kopie des CVS-Systems herunterzuladen und sich dann die aktuellsten Quellen aus dem CVS-Repository xml.apache.org zu holen. Anstatt diesen Weg hier detailliert zu erklären, den wahrscheinlich nur ein geringer Teil der Leser wählt, verweise ich hier auf CVS – kurz & gut von Gregor Purdy (O’Reilly Verlag). Dieses Büchlein, zusammen mit den Anweisungen unter http://xml.apache.org/cvs.html, hilft Ihnen dabei.

Diejenigen unter Ihnen, die Cocoon auf einer Site benutzen wollen, sollten das letzte Cocoon-Binary unter http://xml.apache.org/cocoon/dist herunterladen. Als dieses Buch geschrieben wurde, war die Version 1.8.2 für Windows (Cocoon-1.8.2.zip) und Linux/Unix (Cocoon-1.8.2.tar.gz) verfügbar. Nach dem Download sollten Sie das Archiv in ein temporäres Verzeichnis entpacken. Die wichtigste Sache, auf die Sie hierbei achten sollten, ist das entstandene lib/-Verzeichnis. Dieses Verzeichnis enthält alle Bibliotheken, die benötigt werden, um Cocoon auf der Servlet-Engine laufen zu lassen.

Wenn kein lib/-Verzeichnis entsteht oder es nicht mehrere jar-Files enthält, haben Sie wahrscheinlich eine ältere Version von Cocoon. Nur neuere Releases (1.8 und darüber) enthalten diese Bibliotheken (die das Leben übrigens sehr erleichtern!).

Nachdem die Cocoon-Binaries vorliegen, müssen Sie die Servlet-Engine so einstellen, daß sie Cocoon benutzt, und dann konfigurieren, welche Requests Cocoon bearbeiten soll. Im Blickpunkt soll hier die Zusammenarbeit von Cocoon mit der Jakarta Tomcat Servlet-Engine stehen, da dies die Referenzimplementierung für die Java Servlet API (Version 2.2) ist. Wird eine andere als die Tomcat-Engine benutzt, müssen Sie diese Schritte entsprechend anpassen.

Der erste Schritt besteht darin, alle Bibliotheken, die zur Laufzeit benötigt werden, in das Bibliotheksverzeichnis von Tomcat zu kopieren. Dies ist das Verzeichnis TOMCAT_ HOME/lib, wobei TOMCAT_HOME das Verzeichnis der Tomcat-Installation ist. Unter Windows könnte das zum Beispiel c:\java\jakarta-tomcat sein und unter Linux /usr/local/jakarta-tomcat. Das bedeutet nicht, einfach alles aus dem lib/-Verzeichnis von Cocoon zu kopieren (außer man möchte das). Die zur Laufzeit benötigten jar-Dateien sind:

  • bsfengines.jar (Bean Scripting Framework)
  • bsf.jar (Bean Scripting Framework)
  • fop_0_15_0.jar (FOP)
  • sax-bugfix.jar (SAX-Korrekturen zur Fehlerbehandlung)
  • turbine-pool.jar (Turbine)
  • w3c.jar (W3C)
  • xalan_1_2_D02.jar (Xalan)
  • xerces_1_2.jar (Xerces)

Zusätzlich muß die Datei bin/cocoon.jar von Cocoon in dasselbe Verzeichnis (TOMCAT_ HOME/lib) kopiert werden. Nun haben Sie alle Bibliotheken, die für Cocoon benötigt werden, zusammen.

Die neuesten Versionen von Tomcat (momentan 3.2.1) laden alle Bibliotheken automatisch in das lib/-Verzeichnis von Tomcat. Das bedeutet, daß Sie sich nicht um die Einstellung des Klassenpfades kümmern müssen. Benutzen Sie eine Engine, die dieses automatische Laden nicht implementiert, müssen Sie jedes der genannten jars zum Klassenpfad der Servlet-Engine hinzufügen.

Sind alle Bibliotheken am korrekten Platz, müssen Sie der Servlet-Engine noch mitteilen, in welchem Kontext Cocoon laufen soll. Diese Angabe sagt der Engine zunächst einmal, wo durch Cocoon angeforderte Dateien liegen. Dafür müssen Sie die Datei server.xml im conf/-Verzeichnis von Tomcat modifizieren. Folgende Zeilen müssen am Ende dieser Datei innerhalb des ContextManager-Elements eingefügt werden:

<Server>
  <!-- Other Server elements -->

  <ContextManager>
    <!-- Other Context directives -->

    <Context path="/cocoon" 
             docBase="webapps/cocoon" 
             debug="0"
             reloadable="true" >
    </Context>
  </ContextManager>
</Server>

Mit anderen Worten: Requests, deren URI mit /cocoon beginnt (wie zum Beispiel /cocoon/index.xml), sollen auf den Kontext im angegebenen Verzeichnis (webapps/ cocoon) gemappt werden. Natürlich müssen Sie die Verzeichnisse für den definierten Kontext noch anlegen. In unserem Fall sind das also die Verzeichnisse cocoon und cocoon/WEB-INF im Verzeichnis webapps von Tomcat. Nun sollte die Verzeichnisstruktur ungefähr wie in Abbildung 10-1 aussehen.

Abbildung 10-1: Verzeichnisstruktur des Cocoon-Kontexts
Verzeichnisstruktur des Cocoon-Kontexts

Mit diesem Setup müssen Sie jetzt noch einige Dateien aus der Cocoon-Distribution in den Kontext kopieren. Die Dateien conf/cocoon.properties und src/WEB-INF/web.xml werden von Cocoon in das Verzeichnis TOMCAT_HOME/webapps/cocoon/WEB-INF/ kopiert. Wenn Sie das getan haben, müssen Sie nur noch die gerade kopierte Datei web.xml editieren. Die Referenz darin ist so zu ändern, daß sie auf die gerade kopierte Datei cocoon.properties zeigt:

<web-app>
 <servlet>
  <servlet-name>org.apache.cocoon.Cocoon</servlet-name>
  <servlet-class>org.apache.cocoon.Cocoon</servlet-class>
  <init-param>
   <param-name>properties</param-name>
   <param-value>WEB-INF/cocoon.properties</param-value>
  </init-param>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>org.apache.cocoon.Cocoon</servlet-name>
  <url-pattern>*.xml</url-pattern>
 </servlet-mapping>
</web-app>

Nun muß noch eine letzte, langweilige Änderung an der Installation vorgenommen werden. Tomcat lädt alle jar-Files im lib/-Verzeichnis in ihrer alphabetischen Reihenfolge. Das Problem ist, daß Tomcat eine DOM-Level-1-Implementierung in der Datei parser.jar mitbringt. Cocoon benötigt aber eine DOM-Level-2-Implementierung wie zum Beispiel die von Xerces, welche als xerces_1_2.jar mitgeliefert wird. Wegen der alphabetischen Reihenfolge wird parser.jar vor xerces_1_2.jar geladen und Cocoon steigt aus. Um dieses Problem zu lösen, benennt man parser.jar einfach so um, daß es nach Xerces geladen wird (zum Beispiel nach z_parser.jar). Diese Vorgehensweise garantiert, daß Tomcat immer noch auf die Klassen zugreifen kann, daß die Klassen für DOM Level 2 aber zuerst geladen und daher von Cocoon benutzt werden können.

Nachdem alle genannten Schritte ausgeführt sind, können Sie Cocoon durch das Laden der Cocoon-Informations-URI testen, die Informationen über die Installation liefert. Dazu greifen Sie auf http://[hostname:port]/cocoon/Cocoon.xml zu. In einer Standardinstallation wäre das http://localhost:8080/cocoon/Cocoon.xml. Im Browser sollten Sie Ergebnisse wie in Abbildung 10-2 sehen.

Abbildung 10-2: Überprüfen der Cocoon-Installation
Überprüfen der Cocoon-Installation

An diesem Punkt angekommen, können Sie nun echten Inhalt ins System einbringen. Mit dem Setup, das nun vorliegt, werden alle Requests, die in .xml enden und im Cocoon-Kontext definiert sind, vom Cocoon-Servlet behandelt.

Benutzung eines Publishing Frameworks

Die Benutzung eines guten Publishing Frameworks wie Cocoon verlangt keine spezielle Einarbeitung; es ist keine komplexe Anwendung, an die sich der Nutzer erst anpassen muß. Tatsächlich basiert die Benutzung von Cocoon auf einfachen URLs, die in einen Standard-Web-Browser eingegeben werden. Die Generierung von dynamischen HTML-Seiten aus XML, das Betrachten von XML-Dokumenten als PDF und sogar die Generierung von VRML-Anwendungen aus XML-Dateien erfordert lediglich die Eingabe der entsprechenden URL in einen Browser – danach können Sie Cocoon und der Macht von XML beim Arbeiten zuschauen.

Da nun das Framework installiert ist und korrekt auf .xml endende Requests behandelt, können Sie mit dem Publizieren von XML-Dateien beginnen. Cocoon bringt im Verzeichnis samples/ einige exemplarische XML-Dateien und die zugehörigen XSL-Stylesheets mit. Aus den vorangegangenen Kapiteln existiert schon einiges Material in XML und XSL. Als Beispiel soll daher das XML-Inhaltsverzeichnis dieses Buches (contents.xml) mit dem XSL-Stylesheet (JavaXML.html.xsl) aus dem Kapitel Einstieg in XML transformiert werden.

Dazu müssen Sie das XML-Dokument nach webapps/cocoon/ kopieren. Das Dokument referenziert das Stylesheet XSL/JavaXML.html.xsl. Dafür muß ein Verzeichnis XSL/ angelegt und das Stylesheet in dieses Verzeichnis kopiert werden. Das Dokument referenziert außerdem eine DTD. Entweder kommentieren Sie das aus, oder Sie legen ein entsprechendes Verzeichnis DTD/ an und kopieren JavaXML.dtd aus dem Kapitel Einstieg in XML in dieses Verzeichnis.

Abbildung 10-3: Cocoon bei der Arbeit an contents.xml
Cocoon bei der Arbeit an contents.xml

Wenn das XML-Dokument und das Stylesheet an die richtigen Stellen kopiert worden sind, können Sie mit der URL http://<hostname>:<port>/cocoon/contents.xml im Browser darauf zugreifen. Vorausgesetzt, daß Sie den vorangegangenen Anweisungen zum Setup von Cocoon gefolgt sind, müßte das transformierte Dokument wie in Abbildung 10-3 aussehen.

Das erscheint ziemlich einfach. Sobald Cocoon konfiguriert ist, ist es ein Kinderspiel, dynamische Inhalte zur Verfügung zu stellen! Das Mapping von XML-Erweiterungen auf Cocoon funktioniert für jedweden Request innerhalb des Kontexts, in dem Cocoon eingerichtet ist.

Bei meiner Beschreibung der Nutzung von XML für Präsentationen lag der Schwerpunkt bisher auf der Konvertierung von XML nach HTML. Das ist aber nur eines der Formate, in die man XML-Dokumente konvertieren kann. Als Ziel der Umwandlung können nicht nur viele Markup Languages dienen, Java bietet auch Bibliotheken zur Konvertierung in nicht Markup-basierte Formate an. Die populärste und stabilste Bibliothek in diesem Zusammenhang ist der Formatting Objects Processor (FOP) der Apache-Gruppe. Er gibt Cocoon oder auch anderen Publishing Frameworks die Möglichkeit, XML-Dokumente in das PDF-Format umzuwandeln, das man zum Beispiel mit Adobe Acrobat (http://www.adobe.com) anschauen kann.

Die Bedeutung der Konvertierung von XML nach PDF kann nicht überbewertet werden, besonders für dokumentbasierte Webseiten wie die von Print-Medien-Unternehmen oder Verlagen. Sie könnte die webbasierte Verteilung und Lieferung von Daten revolutionieren. Als Beispiel soll das folgende XML-Dokument dienen – ein mittels XML formatierter Auszug aus diesem Kapitel, wie in Beispiel 10-1 gezeigt.

Ein XSL Stylesheet zur Transformation dieses Dokuments nach HTML wurde bereits gezeigt. Die Konvertierung eines ganzen Kapitels nach HTML würde aber eine gigantische Datei zur Folge haben und sicherlich ein unlesbares Format ergeben; potentielle Leser, die online auf Dokumente zugreifen wollen, wünschen sich außerdem meist PDF als Ausgabeformat. Andererseits bedeutet die Variante mit einem statischen PDF-Dokument, daß man darauf achten muß, daß sich alle Änderungen im entsprechenden Kapitel auch in der PDF-Datei widerspiegeln. Sie müssen das Dokument also ständig neu erzeugen.

Dagegen ist es mit nur einem XML-Dokument möglich, das Dokument einfach zu modifizieren (mit einem XML-Editor), es für den Ausdruck nach SGML zu konvertieren, es zu anderen Unternehmen zu transferieren oder in andere Applikationen zu importieren oder in andere Bücher einzufügen. Wenn man nun noch die Möglichkeit hinzunimmt, daß Web-Nutzer eine URL eingeben und das Dokument im PDF-Format geliefert bekommen, beschreibt dieser Satz an Features ein komplettes Publishing-System.

Beispiel 10-1: XML-Version von Java und XML (Fortsetzung)

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

<?cocoon-process type="xslt"?>
<?xml-stylesheet href="XSL/JavaXML.fo.xsl" type="text/xsl"?>

<book>
 <cover>
  <title>Java und XML</title>
   <author>Brett McLaughlin</author>
 </cover>

 <contents>
  <chapter title="Web Publishing Frameworks" number="10">
      
   <paragraph>  In diesem Kapitel beginnt die Darstellung spezifischer Java- und XML-
Themen. Bisher  wurden die Grundlagen für die Benutzung von XML unter Java 
vorgestellt, ein Blick auf die SAX-, DOM-, JDOM- und JAXP-APIs zur Manipulation 
von XML geworfen und schließlich die Grundlagen der Benutzung und Erzeugung 
von XML selbst diskutiert. Nachdem Sie jetzt wissen, wie Sie XML von Ihrem Code 
aus benutzen können, wenden wir uns jetzt spezifischen Applikationen zu. 
Die nächsten sechs Kapitel beschäftigen sich mit den wichtigsten Anwendungen von 
XML und speziell damit, wie diese Anwendungen im Java-Umfeld implementiert sind. 
Während es natürlich Tausende von wichtigen Anwendungen von XML gibt, sind die 
in den folgenden Kapiteln vorgestellten solche, die durch ihr Potential,
die Herangehensweise an Entwicklungsprozesse drastisch zu ändern, ständig im  
Blickpunkt stehen.
   </paragraph>

    <sidebar title="Je mehr sich Dinge ändern, desto mehr bleiben sie die alten">
Leser der ersten Auflage werden bemerken, daß vieles bei der 
Erläuterung von Cocoon in diesem Kapitel gleichgeblieben ist. Obwohl ich
versprochen habe, daß Cocoon 2 nun fertig wäre, und ich eigentlich darüber schreiben
wollte, ist die Entwicklung nicht so schnell fortgeschritten wie erwartet.
Stefano Mazzochi, die treibende Kraft hinter Cocoon, hat sich dazu durchgerungen, 
die Schule abzuschließen (gute Entscheidung, Stefano!), und dadurch wurde die
Entwicklung von Cocoon 2 verlangsamt. Cocoon 1.x  ist nach wie vor die aktuelle 
Version, an die man sich halten sollte. Ich habe den Abschnitt über Cocoon 2 so 
aktualisiert, daß er widerspiegelt, was kommen wird. Halten Sie in den nächsten
Monaten Ausschau nach mehr O’Reilly-Büchern zum Thema Cocoon.</sidebar>

   <paragraph> Die erste heiße Sache, der wir uns zuwenden werden, ist die
XML-Anwendung, die die meiste Begeisterung in der XML- und Java-Gemeinde ausgelöst
hat: die Web Publishing Frameworks. Ich habe ständig betont, daß die Möglichkeit, 
die Präsentation aus dem Inhalt zu erzeugen, zu Ungunsten des Wertes der portablen 
Darstellung, die XML zur Verfügung stellt, überbewertet wird. Die Benutzung 
von XML zur Präsentation ist jedoch nach wie vor sehr wichtig. Diese Wichtigkeit 
erhöht sich noch mit Blick auf Web-Anwendungen.</paragraph> 
  </chapter>

 </contents>
</book>

Dieses Buch beschreibt Formatting Objects und den FOP für Java-Bibliotheken nicht im Detail, Sie können aber die vollständige Formatting Objects-Definition in der XSL-Spezifikation des W3C unter http://www.w3.org/TR/xsl/ einsehen. Beispiel 10-2 ist ein XSL-Stylesheet, das Formatting Objects benutzt, um eine für dieses Kapitel passende Transformation von XML in ein PDF-Dokument zu spezifizieren.

Beispiel 10-2: XSL-Stylesheet für die PDF-Transformation (Fortsetzung)

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fo="http://www.w3.org/1999/XSL/Format">

  <xsl:template match="book">
    <xsl:processing-instruction name="cocoon-format">
      type="text/xslfo"
    </xsl:processing-instruction>
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <fo:layout-master-set>
      <fo:simple-page-master
        master-name="right"
        margin-top="75pt"
        margin-bottom="25pt"
        margin-left="100pt"
        margin-right="50pt">
        <fo:region-body margin-bottom="50pt"/>
        <fo:region-after extent="25pt"/>
      </fo:simple-page-master>
      <fo:simple-page-master
        master-name="left"
        margin-top="75pt"
        margin-bottom="25pt"
        margin-left="50pt"
        margin-right="100pt">
        <fo:region-body margin-bottom="50pt"/>
        <fo:region-after extent="25pt"/>
      </fo:simple-page-master>
      <fo:page-sequence-master master-name="psmOddEven">
        <fo:repeatable-page-master-alternatives>
          <fo:conditional-page-master-reference 
              master-name="right" 
              page-position="first"/>
          <fo:conditional-page-master-reference 
              master-name="right" 
              odd-or-even="even"/>
          <fo:conditional-page-master-reference 
              master-name="left" 
              odd-or-even="odd"/>
          <!-- recommended fallback procedure -->
          <fo:conditional-page-master-reference 
              master-name="right"/>
        </fo:repeatable-page-master-alternatives>
      </fo:page-sequence-master>
      </fo:layout-master-set>

      <fo:page-sequence master-name="psmOddEven">

        <fo:static-content flow-name="xsl-region-after">
          <fo:block text-align-last="center" font-size="10pt">
            <fo:page-number/>
          </fo:block>
        </fo:static-content>

        <fo:flow flow-name="xsl-region-body">
          <xsl:apply-templates/>
        </fo:flow>
      </fo:page-sequence>

    </fo:root>
  </xsl:template>

  <xsl:template match="cover">
    <fo:block font-size="10pt" 
              space-before.optimum="10pt">
      <xsl:value-of select="title"/>
      (<xsl:value-of select="author"/>)
    </fo:block>    
  </xsl:template>

  <xsl:template match="contents">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="chapter">
    <fo:block font-size="24pt" 
              text-align-last="center" 
              space-before.optimum="24pt">
      <xsl:value-of select="@number" />.
      <xsl:value-of select="@title" />
      <xsl:apply-templates/>
    </fo:block>
  </xsl:template>

  <xsl:template match="paragraph">
    <fo:block font-size="12pt" 
              space-before.optimum="12pt" 
              text-align="justify">
      <xsl:apply-templates/>
    </fo:block>
  </xsl:template>
  
  <xsl:template match="sidebar">
    <fo:block font-size="14pt"
              font-style="italic"
              color="blue" 
              space-before.optimum="16pt" 
              text-align="center">
      <xsl:value-of select="@title" />
    </fo:block>
    <fo:block font-size="12pt"
              color="blue" 
              space-before.optimum="16pt" 
              text-align="justify">
      <xsl:apply-templates/>
    </fo:block>
  </xsl:template>  
</xsl:stylesheet>

Wenn Sie diese beiden Dateien erzeugt und das Kapitel als chapterTen.xml und das Stylesheet als JavaXML.fo.xsl im Verzeichnis XSL/ gespeichert haben, können Sie das Resultat in einem Browser bewundern. Dazu wird das Adobe Acrobat Reader-Plugin für den entsprechenden Webbrowser benötigt. Das Resultat ist in Abbildung 10-4 zu sehen.

Abbildung 10-4: Resultat der Transformation von chapterTen.xml nach PDF
Resultat der Transformation von chapterTen.xml nach PDF

Zusätzlich zu der Möglichkeit, speziell bestimmte Transformationen anzufordern, wie zum Beispiel die gezeigte Transformation nach PDF, erlaubt es Cocoon auch, eine dynamische Verarbeitung durchzuführen, die vom jeweiligen Request abhängt. Ein verbreitetes Beispiel dafür ist es, verschiedene Transformationen abhängig vom Medium des Clients durchzuführen. In einer traditionellen Web-Umgebung wird es dadurch möglich, ein XML-Dokument abhängig vom verwendeten Browser verschieden zu transformieren. Ein Client, der den Internet Explorer benutzt, könnte eine andere Präsentation übermittelt bekommen als einer, der zum Beispiel Netscape benutzt. Denkt man an die letzten Kriege zwischen verschiedenen Versionen von HTML, DHTML und JavaScript, die sich zwischen Microsoft und Netscape abgespielt haben, ist das ein sehr machtvolles Feature.

Cocoon bietet von Haus aus Unterstützung für viele Browsertypen. Die Datei cocoon.properties, auf die ich weiter vorn schon eingegangen bin, enthält am Ende folgenden Abschnitt (dies kann bei neueren Versionen ein wenig abweichen):

##########################################
# User Agents (Browsers)                 #
##########################################

# Achtung: Die Zahlen geben die Suchreihenfolge an. Das ist SEHR, SEHR WICHTIG, 
# da einige Wörter in mehr als einer Browser-Beschreibung vorkommen können. 
# (MSIE wird durch "Mozilla/4.0 (Compatible; MSIE 4.01; ...") repräsentiert.)
#
# Zum Beispiel besagt das Tag "explorer=MSIE", daß das XSL-Stylesheet
# des Medientyps  "explorer" für die Browser verwendet werden soll, die 
# den String "MSIE" in ihrem "user-Agent"-HTTP-Header haben.

browser.0 = explorer=MSIE
browser.1 = pocketexplorer=MSPIE
browser.2 = handweb=HandHTTP
browser.3 = avantgo=AvantGo
browser.4 = imode=DoCoMo
browser.5 = opera=Opera
browser.6 = lynx=Lynx
browser.7 = java=Java
browser.8 = wap=Nokia
browser.9 = wap=UP
browser.10 = wap=Wapalizer
browser.11 = mozilla5=Mozilla/5
browser.12 = mozilla5=Netscape6/
browser.13 = netscape=Mozilla

Die Schlüsselwörter nach dem ersten Gleichheitszeichen sind die, um die es geht: explorer, lynx, java und mozilla5 zum Beispiel unterscheiden alle verschiedene User-Agents – die Codes, die die Browser mit URL-Requests senden. Als Beispiel der davon abhängigen Anwendung von Stylesheets soll ein XSL-Stylesheet dienen, das benutzt wird, wenn ein Client auf die XML-Version des Inhaltsverzeichnisses (contents.xml) mit dem Internet Explorer zugreift. Dazu müssen Sie zunächst eine Kopie des originalen XML-to-HTML-Stylesheets, JavaXML.html.xsl, unter dem Namen JavaXML.explorer-html.xsl anlegen. In dieser Datei müssen Sie nun die in Beispiel 10-3 gezeigten Änderungen durchführen.

Beispiel 10-3: Modifiziertes XSL-Stylesheet für den Internet Explorer

<?xml version="1.0"?>

<xsl:stylesheet xmlns:javaxml2="http://www.oreilly.com/javaxml2"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ora="http://www.oreilly.com"
                version="1.0"
>

  <xsl:template match="javaxml2:book">
  <xsl:processing-instruction name="cocoon-format">
    type="text/html"
  </xsl:processing-instruction>
    <html>
      <head>
        <title>          <xsl:value-of select="javaxml2:title" /> (Explorer Version)        </title>
      </head>
      <body>
        <xsl:apply-templates select="*[not(self::javaxml2:title)]" />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="javaxml2:contents">
    <center>
     <h2>Table of Contents (Explorer Version)</h2>     <small>       Try <a href="http://www.mozilla.org">Mozilla</a> today!     </small>
    </center>
    <!-- Andere XSL-Direktiven -->
  </xsl:template>

  <!-- Andere XSL-Template-Matches -->

</xsl:stylesheet>

Auch wenn das ein recht triviales Beispiel ist, könnte man DHTML für den Internet Explorer 5.5 einfügen und normales HTML für Netscape Navigator oder Mozilla, die nicht so guten DHTML-Support bieten. So vorbereitet müssen Sie dem XML-Dokument nur noch mitteilen, daß es – wenn der Medientyp (oder User-Agent) mit dem in der Eigenschaftsdatei definierten Browsertyp übereinstimmt – ein anderes XSL-Stylesheet benutzen soll. Die dafür nötigen zusätzlichen Anweisungen werden, wie in Beispiel 10-4 gezeigt, zur Datei contents.xml hinzugefügt.

Ein Zugriff auf das Dokument mittels Netscape erzielt dasselbe Resultat wie zuvor, nach einem Zugriff mit dem Internet Explorer sieht man aber, daß es mit einem anderen Stylesheet transformiert wurde, und erhält das in Abbildung 10-5 dargestellte Resultat.

Abbildung 10-5: contents.xml, dargestellt mit dem Internet Explorer
contents.xml, dargestellt mit dem Internet Explorer

Beispiel 10-4: Modifizierte Datei contents.xml zur Beachtung des Medientyps

<?xml version="1.0"?>
<!DOCTYPE Book SYSTEM "DTD/JavaXML.dtd">
<?xml-stylesheet href="XSL/JavaXML.html.xsl" type="text/xsl"?>
<?xml-stylesheet href="XSL/JavaXML.explorer-html.xsl" type="text/xsl"
                 media="explorer"?>

<?cocoon-process type="xslt"?>

<!-- Java und XML-Inhalte -->
<book xmlns="http://www.oreilly.com/javaxml2"
      xmlns:ora="http://www.oreilly.com"
>
  <!-- XML-Inhalt -->
</book>

Eine der großen Stärken dieser dynamischen Anwendung von Stylesheets ist das Zusammenspiel mit Geräten zur drahtlosen Kommunikation. Werfen wir noch einen Blick auf die Eigenschaftsdatei:

##########################################
# User Agents (Browsers)                 #
##########################################

# Achtung: Die Zahlen geben die Suchreihenfolge an. Das ist SEHR, SEHR WICHTIG, 
# da einige Wörter in mehr als einer Browser-Beschreibung vorkommen können. 
# (MSIE wird durch "Mozilla/4.0 (Compatible; MSIE 4.01; ...") repräsentiert.)
#
# Zum Beispiel besagt das Tag "explorer=MSIE", daß das XSL-Stylesheet
# des Medientyps  "explorer" für die Browser verwendet werden soll, die 
# den String "MSIE" in ihrem "user-Agent"-HTTP-Header haben.

browser.0 = explorer=MSIE
browser.1 = pocketexplorer=MSPIE
browser.2 = handweb=HandHTTP
browser.3 = avantgo=AvantGo
browser.4 = imode=DoCoMo
browser.5 = opera=Opera
browser.6 = lynx=Lynx
browser.7 = java=Java
browser.8 = wap=Nokiabrowser.9 = wap=UPbrowser.10 = wap=Wapalizer
browser.11 = mozilla5=Mozilla/5
browser.12 = mozilla5=Netscape6/
browser.13 = netscape=Mozilla

Die hervorgehobenen Einträge ermitteln, daß ein drahtloser Agent, wie zum Beispiel ein internetfähiges Mobiltelefon genutzt wird, um auf den Inhalt zuzugreifen. Genau wie Cocoon bemerkt hat, ob der benutzte Browser Netscape oder der Internet Explorer war, und darauf mit dem korrekten Stylesheet antwortete, kann ein WAP-Gerät ebenfalls mittels eines speziellen Stylesheets bedient werden. Dazu fügt man eine weitere Referenz auf ein Stylesheet in die Datei contents.xml ein:

<?xml version="1.0"?>
<!DOCTYPE Book SYSTEM "DTD/JavaXML.dtd">
<?xml-stylesheet href="XSL/JavaXML.html.xsl" type="text/xsl"?>
<?xml-stylesheet href="XSL/JavaXML.explorer-html.xsl" type="text/xsl"
                 media="explorer"?>
<?xml-stylesheet href="XSL/JavaXML.wml.xsl" type="text/xsl"                  media="wap"?>                 

<?cocoon-process type="xslt"?>

<!-- Java- und XML-Inhalte-->
<book xmlns="http://www.oreilly.com/javaxml2"
      xmlns:ora="http://www.oreilly.com"
>
  <!-- XML-Inhaltsverzeichnis-->
</book>

Nun müssen Sie noch das neu referenzierte Stylesheet für WAP-Geräte erzeugen. Die Wireless Markup Language (WML) wird typischerweise benutzt, wenn ein Stylesheet für ein WAP-Gerät erstellt wird. WML ist eine Variante von HTML mit einer geringfügig anderen Methode der Repräsentation verschiedener Seiten. Wenn ein drahtloses Gerät eine URL anfordert, muß die Antwort innerhalb eines wml-Elements erfolgen. In diesem root-Element (Wurzel-Element) sind verschiedene cards (Karten) definiert, jede durch das WML-Element card. Das Endgerät lädt mehrere dieser Karten auf einmal herunter, damit nicht für jede neue Seite wieder ein Serverzugriff nötig ist. Eine solche Menge von Karten wird auch oft als deck (engl. für Stapel) bezeichnet. Beispiel 10-5 zeigt eine einfache WML-Seite, die diese Konstrukte benutzt.

Dieses einfache Beispiel zeigt auf Abfrage ein Menü und definiert zwei Seiten, auf die über Links von diesem Menü aus zugegriffen werden kann. Die vollständige WML 1.1-Spezifikation ist online mit einigen anderen WAP-Spezifikationen unter http://www.wapforum.org/what/technical_1_1.htm verfügbar. Sie können außerdem auf das Buch Learning WML and WMLScript von Martin Frost (O’Reilly & Associates) zurückgreifen. Zusätzlich können Sie das UP.SDK unter http://www.phone.com/products/upsdk.html herunterladen; diese Software emuliert ein drahtloses Endgerät und erlaubt es, erstellte WML-Seiten zu testen. Damit können Sie XSL-Stylesheets für die Ausgabe von WML auf WAP-Endgeräten entwickeln und die Ergebnisse mit dem Browser des UP.SDK unter http://<hostname>:<port>/contents.xml testen.

Beispiel 10-5: Eine einfache WML-Seite

<wml>
 <card id="index" title="Home Page">
  <p align="left">
   <i>Hauptmen&uuml;</i><br />
   <a href="#title">Titelseite</a><br />
   <a href="#myPage">Meine Seite</a><br />
  <p>
 </card>

 <card id="title" title="Meine Titelseite">
  Willkommen auf  meiner Titelseite!<br />
  Ich bin so gl&uuml;cklich, Dich zu sehen.
 </card>

 <card id="myPage" title="Hallo, Welt">
  <p align="center">
   Hallo, Welt!
  </p>
 </card>
</wml>

Da die Displays von Mobiltelefonen sehr viel kleiner als Computerbildschirme sind, soll nur eine Untermenge der Informationen des XML-Inhaltsverzeichnisses angezeigt werden. Beispiel 10-6 ist ein XSL-Stylesheet, das drei Cards in WML erzeugt. Die erste ist ein Menü mit Links zu den zwei anderen. Die zweite generiert eine Auflistung des Inhaltsverzeichnisses aus der Datei contents.xml. Die dritte schließlich ist eine Seite, die eine einfache Copyright-Notiz enthält. Dieses Stylesheet wird unter JavaXML.wml.xsl im XSL/-Verzeichnis des Cocoon-Kontexts gespeichert.

Beispiel 10-6: WML-Stylesheet (Fortsetzung)

<?xml version="1.0"?>

<xsl:stylesheet version="1.0"                 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:javaxml2="http://www.oreilly.com/javaxml2"
                xmlns:ora="http://www.oreilly.com"
                exclude-result-prefixes="javaxml2 ora"
>

 <xsl:template match="javaxml2:book">
  <xsl:processing-instruction name="cocoon-format">
    type="text/wml"
  </xsl:processing-instruction>

  <wml>
   <card id="index" title="{javaxml2:title}">
    <p align="center">
     <i><xsl:value-of select="javaxml2:title"/></i><br />
     <a href="#contents">Inhalte</a><br/>
     <a href="#copyright">Copyright</a><br/>
    </p>
   </card>
   
   <xsl:apply-templates select="javaxml2:contents" />

   <card id="copyright" title="Copyright">
    <p align="center">
     Copyright 2000, O&apos;Reilly &amp; Associates
    </p>
   </card>
  </wml>
 </xsl:template>
 
 <xsl:template match="javaxml2:contents">
  <card id="contents" title="Inhalte">
   <p align="center">
    <i>Contents</i><br />
    <xsl:for-each select="javaxml2:chapter">
     <xsl:value-of select="@number" />.
     <xsl:value-of select="@title" /><br />
    </xsl:for-each>
   </p>
  </card>
 </xsl:template>

</xsl:stylesheet>

Bis auf die WML-Tags sollte das Beispiel vertraut aussehen. Es gibt eine Verarbeitungsanweisung für Cocoon mit dem Ziel cocoon-format. Die gesendeten Daten vom Typ type="text/wml" weisen Cocoon an, dieses Stylesheet mit einem Content Header auszuliefern, der anzeigt, daß der Inhalt text/wml (statt des normalen text/html oder text/plain) ist. Es gibt noch eine weitere wichtige Erweiterung – ein zum root-Element des Stylesheets hinzugefügtes Attribut:

<?xml version="1.0"?>

<xsl:stylesheet version="1.0"                 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:javaxml2="http://www.oreilly.com/javaxml2"
                xmlns:ora="http://www.oreilly.com"
                exclude-result-prefixes="javaxml2 ora"
>

Normalerweise werden irgendwelche den XML-Namensraum betreffenden Deklarationen, die nicht dem XSL-Namensraum angehören, dem root-Element des transformierten Ergebnisses hinzugefügt. In diesem Beispiel würden dem root-Element des transformierten Ergebnisses (wml) die mit den javaxml2- und ora-Präfixen verbundenen Namensraum-Deklarationen hinzugefügt:

<wml xmlns:javaxml2="http://www.oreilly.com/javaxml2"
     xmlns:ora="http://www.oreilly.com"
>
  <!-- WML-Inhalt -->
</wml>

Dies führt dazu, daß ein WAP-Browser einen Fehler meldet, denn xmlns:javaxml2 und xmlns:ora sind keine erlaubten Attribute für das wml-Element. WAP-Browser sind nicht so nachsichtig wie HTML-Browser, und der Rest der WML-Seite würde nicht angezeigt. Sie müssen den Namensraum jedoch deklarieren, damit das XSL-Stylesheet das Template-Matching für das Quelldokument durchführen kann, welches den javaxml zugeordneten Namensraum benutzt. Um dieses Problem zu lösen, erlaubt es XSL, das Attribut exclude-result-prefixes zum xsl:stylesheet-Element hinzuzufügen. Das Namensraum-Präfix, das in diesem Attribut angegeben wird, wird nicht zum transformierten Ergebnis hinzugefügt, was genau unser Problem löst. Das Resultat sieht nun folgendermaßen aus:

<wml>
  <!-- WML-Inhalt -->
</wml>

Das wird von einem WAP-Browser wunderbar verstanden. Wenn Sie den UP.SDK-Browser heruntergeladen haben, können Sie damit auf das XML-Inhaltsverzeichnis zeigen und die Resultate bewundern. Abbildung 10-6 zeigt das Hauptmenü als Resultat der Transformation mit dem XML-Stylesheet, wenn ein WAP-Endgerät die Datei contents.xml über Cocoon anfordert.

Abbildung 10-6: Hauptmenü für Java und XML
Hauptmenü für Java und XML

In der Version des UP.SDK-Browsers, die ich getestet habe, konnte die Referenz OReillyCopyright nicht aufgelöst werden. Ich mußte diese Zeile im XML auskommentieren, damit das Beispiel funktionierte. Sie werden das wahrscheinlich auch machen müssen, sollte dieser Bug noch nicht behoben sein.

Abbildung 10-7 zeigt das generierte Inhaltsverzeichnis, das Sie aufrufen, wenn Sie die »Link«-Schaltfläche aktivieren, wenn der Eintrag »Contents« angewählt ist.

Abbildung 10-7: WML-Inhaltsverzeichnis
WML-Inhaltsverzeichnis

Weitere Informationen zum Thema Entwicklung für drahtlose Endgeräte finden Sie unter http://www.openwave.com2 und http://www.wapforum.org. Beide halten ausführliche Informationen zu den Themen WML und WAP bereit.

An diesem Punkt sollte klar sein, wie groß die Vielfalt an Möglichkeiten ist, verschiedenste Ausgaben mittels Cocoon zu erzeugen. Mit einem minimalen Arbeitsaufwand und einem zusätzlichen Stylesheet kann dasselbe XML-Dokument verschiedenen Arten von Clients in unterschiedlichen Formaten geliefert werden. Das ist nur ein Grund, warum Publishing Frameworks solch leistungsfähige Werkzeuge darstellen. Ohne XML und ein solches Framework müßten Sie für jede Art von Client eine eigene Site aufsetzen. Nachdem hier die Flexibilität bei der Generierung von Output mittels Cocoon beleuchtet wurde, wenden wir uns nun der Technologie innerhalb von Cocoon zu, die die dynamische Generierung und Anpassung des Inputs für diese Transformationen erlaubt.

XSP

XSP steht für Extensible Server Pages und ist vielleicht die wichtigste Entwicklung im Rahmen des Cocoon-Projekts. JavaServer Pages (JSP) erlauben es, Tags und inline Java-Code in eine ansonsten normale HTML-Seite zu integrieren. Wenn die JSP-Seite angefordert wird, wird der Code ausgeführt und die Ergebnisse werden in das endgültige HTML-Format eingesetzt.3 Dieses Verfahren hat die Welt von Java und ASP im Sturm erobert, weil es vorgab, die serverseitige Java-Programmierung zu vereinfachen und die Separation von Inhalt und Präsentation zu erlauben. Dennoch sind einige wichtige Probleme noch immer nicht gelöst.

Zunächst führen JSP nicht wirklich zu einer Trennung von Inhalt und Präsentation. Dieses Problem wurde schon einmal angesprochen: Änderungen an einem Banner, an der Schriftfarbe oder an der Schriftgröße erfordern es, die JSP (einschließlich des inline-Java und der JavaBeans-Referenzen) zu ändern. JSP vermischen außerdem Inhalt (die puren Daten) mit der Präsentation genauso, wie es auch mit statischem HTML passiert. Weiterhin existiert keine Möglichkeit, die JSP in irgendein anderes Format zu konvertieren oder sie anwendungsübergreifend zu benutzen, da die JSP-Spezifikation hauptsächlich für die Generierung von Output entworfen wurde.

XSP beendet diese Probleme. XSP ist unter der Haube einfach XML. Vergleichen Sie dazu die einfache XSP-Seite in Beispiel 10-7.

Beispiel 10-7: Eine einfache XSP-Seite

<?xml version="1.0" encoding="ISO-8859-1"?>
<?cocoon-process type="xsp"?>
<?cocoon-process type="xslt"?>
<?xml-stylesheet href="myStylesheet.xsl" type="text/xsl"?>

<xsp:page language="java" 
          xmlns:xsp="http://www.apache.org/1999/XSP/Core"
>
 
 <xsp:logic>
  private static int numHits = 0; 
  
  private synchronized int getNumHits(  ) { 
   return ++numHits; 
  }
 </xsp:logic>

 <page>
  <title>Zugriffszähler</title>
 
  <p>Auf mich wurde schon <xsp:expr>getNumHits(  )</xsp:expr> mal zugegriffen.</p>
 </page>
</xsp:page>

Allen XML-Konventionen wird Genüge getan. Im Moment soll der Inhalt des xsp:logic-Elements einfach vom XML-Parser »ignoriert« werden; dazu später mehr. Ansonsten ist das Dokument einfach XML mit ein paar neuen Elementen. Es referenziert ein XSL-Stylesheet, das nichts Bemerkenswertes an sich hat, wie man in Beispiel 10-8 sehen kann.

Beispiel 10-8: Ein XSL-Stylesheet für die XSP-Seite

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
>

  <xsl:template match="page">
    <xsl:processing-instruction name="cocoon-format">
      type="text/html"
    </xsl:processing-instruction>
    <html>
      <head>
        <title><xsl:value-of select="title"/></title>
      </head>
      <body>
        <xsl:apply-templates select="*[not(self::title)]" />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="p">
    <p align="center">
      <xsl:apply-templates />
    </p>
  </xsl:template>

</xsl:stylesheet>

Aus diesem Grunde behandelt XSP das erste größere Problem von JSP mit Leichtigkeit: Es trennt den Inhalt von der Präsentation. Diese Trennung erlaubt es Entwicklern, sich um die Generierung des Inhalts zu kümmern (die XSP-Seite kann von einem Servlet oder von anderem Java-Code genauso generiert werden, wie sie auch statisch vorliegen kann). XML- und XSL-Autoren können sich ganz auf die Präsentation und die Formatierung durch Modifikationen am für die jeweilige XSP-Seite zuständigen XSL-Stylesheet beschäftigen. Genausoleicht löst XSP das andere große Defizit von JSP: Da die Verarbeitung von XSP geschieht, bevor irgendein Stylesheet zur Anwendung kommt, kann das Resultat einfach in andere Formate konvertiert werden. XSP erbt alle Vorteile von XML, da eine XSP-Seite einfach zwischen Anwendungen ausgetauscht werden wie auch zur Präsentation benutzt werden kann.

Nach den einführenden Wörtern zu XSP wir es nun Zeit, selbst eine XSP-Seite zu erstellen. Für dieses Beispiel werden die schon vorhandenen XML-Dokumente weitergenutzt. Wir befassen uns zunächst mit dem XML-Dokument, das einen Ausschnitt dieses Kapitels darstellt. Dieses Dokument ist nach PDF konvertiert worden. Damit könnte es der Autor seinem Lektor ermöglichen, das Dokument zu sehen, während er daran arbeitet. Zusätzlich soll es aber auch möglich sein, daß der Lektor Bemerkungen des Autors einsehen kann, die anderen Lesern verborgen bleiben sollen: Zum Beispiel Fragen zum Stil und der Formatierung. Dazu wird zunächst die folgende Bemerkung in das Dokument chapterTen.xml eingefügt:

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

<?cocoon-process type="xslt"?>
<?xml-stylesheet href="XSL/JavaXML.fo.xsl" type="text/xsl"?>

<book>
 <cover>
  <title>Java und XML</title>
  <author>Brett McLaughlin</author>
 </cover>

 <contents>
  <chapter title="Web Publishing Frameworks" number="10">
      
   <paragraph> In diesem Kapitel beginnt die Darstellung spezifischer Java- und
XML-Themen. Bisher  wurden die Grundlagen für die Benutzung von XML unter Java
vorgestellt, ein Blick auf die SAX-, DOM-, JDOM- und JAXP-APIs zur Manipulation 
von XML geworfen und schließlich die Grundlagen der Benutzung und Erzeugung von 
XML selbst diskutiert. Nachdem Sie jetzt wissen, wie Sie XML von Ihrem Code aus 
benutzen können, wenden wir uns jetzt spezifischen Applikationen zu. Die nächsten 
sechs Kapitel beschäftigen sich mit den wichtigsten Anwendungen von XML und 
speziell damit, wie diese Anwendungen im Java-Umfeld implementiert sind. Während 
es natürlich Tausende von wichtigen Anwendungen von XML gibt, sind die in den 
folgenden Kapiteln vorgestellten solche, die durch ihr Potential, die 
Herangehensweise an Entwicklungsprozesse drastisch zu ändern, ständig im 
Blickpunkt stehen. 
   </paragraph>
   
   <authorComment>Mike - Denkst Du, daß der folgende Einschub zu umfangreich        ist? Ich könnte ihn auch weglassen, wenn es dann immer noch         klar ist.   </authorComment>

    <sidebar title="Je mehr sich Dinge ändern, desto mehr bleiben sie die alten">
Leser der ersten Auflage werden bemerken, daß vieles bei der Erläuterung von 
Cocoon in diesem Kapitel gleichgeblieben ist. Obwohl ich versprochen habe, daß 
Cocoon 2 nun fertig wäre, und ich eigentlich darüber schreiben wollte, ist die 
Entwicklung nicht so schnell fortgeschritten wie erwartet. Stefano Mazzochi, die 
treibende Kraft hinter Cocoon, hat sich dazu durchgerungen, die Schule 
abzuschließen (gute Entscheidung, Stefano!), und dadurch wurde die Entwicklung von 
Cocoon 2 verlangsamt. Cocoon 1.x  ist nach wie vor die aktuelle Version, an die 
man sich halten sollte. Ich habe den Abschnitt über Cocoon 2 so aktualisiert, daß 
er widerspiegelt, was kommen wird. Halten Sie in den nächsten Monaten Ausschau 
nach mehr O’Reilly-Büchern zum Thema Cocoon</sidebar>

   <paragraph> Die erste heiße Sache, der wir uns zuwenden werden, ist die XML-
Anwendung, die die meiste Begeisterung in der XML- und Java-Gemeinde ausgelöst 
hat: die Web Publishing Frameworks. Ich habe ständig betont, daß die Möglichkeit, 
die Präsentation aus dem Inhalt zu erzeugen, zu Ungunsten des Wertes der portablen 
Darstellung, die XML zur Verfügung stellt, überbewertet wird. Die Benutzung von 
XML zur Präsentation ist jedoch nach wie vor sehr wichtig. Diese Wichtigkeit 
erhöht sich noch mit Blick auf Web-Anwendungen</paragraph>
  </chapter>

 </contents>
</book>

Wegen dieser Anmerkung im XML-Dokument ist noch ein Eintrag im entsprechenden XSLStylesheet JavaXML.fo.xsl nötig:

  <xsl:template match="sidebar">
    <fo:block font-size="14pt"
              font-style="italic"
              color="blue" 
              space-before.optimum="16pt" 
              text-align="center">
      <xsl:value-of select="@title" />
    </fo:block>
    <fo:block font-size="12pt"
              color="blue" 
              space-before.optimum="16pt" 
              text-align="justify">
      <xsl:apply-templates/>
    </fo:block>
  </xsl:template>

  <xsl:template match="authorComment">   <fo:block font-size="10pt"              font-style="italic"              color="red"              space-before.optimum="12pt"              text-align="justify">     <xsl:apply-templates/>   </fo:block>  </xsl:template>

Die Anmerkungen erscheinen ein wenig kleiner als der Rest des Texts, kursiv und in roter Farbe. Nun ist es möglich, das XML-Dokument (wie in Beispiel 10-9 gezeigt) durch Hinzufügen von Verarbeitungsanweisungen für Cocoon und durch das Einschließen der Elemente durch ein neues root-Element (xsp:page) in eine XSP-Seite zu verwandeln.

Beispiel 10-9: Verwandlung von chapterTen.xml in eine XSP-Seite

<?xml version="1.0"?>

<?cocoon-process type="xsp"?>
<?cocoon-process type="xslt"?>
<?xml-stylesheet href="XSL/JavaXML.fo.xsl" type="text/xsl"?>

<xsp:page language="java"          xmlns:xsp="http://www.apache.org/1999/XSP/Core">
<book>
 <cover>
  <title>Java und XML</title>
  <author>Brett McLaughlin</author>
 </cover>

 <contents>
  <chapter title="Web Publishing Frameworks" number="10">
  <!-- Text des Kapitels -->
  </chapter>
 </contents>
</book>
</xsp:page>

Bevor nun die XSP-Logik für die Entscheidung, ob die Anmerkungen gezeigt werden sollen, geschrieben wird, wird noch eine einfache HTML-Seite erzeugt, die es dem Nutzer erlaubt anzugeben, ob er der Lektor für das Buch ist. In einer realen Anwendung könnte das die Seite sein, die die Authentifizierung regelt und die Rolle des Nutzers ermittelt; für dieses Beispiel kann man zwischen Autor, Lektor und neugierigem Nutzer wählen. Außerdem wird ein Paßwort zur Verifikation verlangt. Die HTML-Seite dazu wird in Beispiel 10-10 gezeigt. Diese Datei wird als entry.html in der Dokumentwurzel des Kontexts gespeichert.

Beispiel 10-10: Startseite für chapterTen.xml als XSP-Seite

<html>
 <head>
  <title>Willkommen bei dem in der Entstehung begriffenen Buch Java und XML</title>
 </head>

 <body>
  <h1 align="center">Das Buch <i>Java und XML</i> in der Entstehung</h1>
  <center>
   <form action="/cocoon/chapterTen.xml" method="POST">
    Select your role:
    <select name="userRole">
     <option value="author">Autor</option>
     <option value="editor">Lektor</option>
     <option value="reader">Leser</option>
    </select>
    <br />
    Geben Sie Ihr Pa&szlig;wort ein:
    <input type="password" name="password" size="8" />
    <br /><br />
    <input type="submit" value="Bring mich zum Buch!" />
   </form>
  </center>
 </body>
</html>

Diese HTML-Seite sendet die Form-Daten direkt an die XSP-Seite. In diesem Beispiel arbeitet die XSP-Seite wie ein Servlet. Sie liest die übergebenen Parameter, bestimmt, welche Nutzerrolle gewählt wurde, authentifiziert diese mittels des Paßworts und entscheidet letztlich, ob die Kommentare angezeigt werden sollen oder nicht. Dazu wird zunächst eine boolean-Variable definiert, die das Resultat des Vergleichs der Request-Parameter daraufhin enthält, ob der Nutzer Autor oder Lektor ist und das korrekte Paßwort angab. Der Wert dieser Variablen wird geprüft, und wenn er true ist, werden die authorComment-Elemente angezeigt. Dazu müssen diese in die hier gezeigten XSP-Direktiven eingeschlossen werden:

Das sieht auch nicht sehr seltsam aus; außer den XSP-spezifischen Tags wird nur eine Variable definiert und getestet. Wenn die Variable true ist, wird das authorComment-Element in die Ausgabe der XSP-Seite eingefügt. Wenn der Wert false ist, wird es ignoriert. Eine interessante Sache, auf die ich noch hinweisen möchte, ist, daß der eigentliche XML-Teil innerhalb eines xsp:content-Elements in einen xsp:logic-Block eingeschlossen ist (der wiederum innerhalb des äußeren xsp:page-Elements steht), um sicherzustellen, daß der XSP-Prozessor nicht versucht, Elemente oder Text innerhalb des Blocks als XSP-Strukturen zu interpretieren. Die gleiche Funktionalität könnte in JSP wie folgt aussehen:

<%
 if (authorOrEditor) {
%>
        <authorComment>Mike - Denkst Du, daß der folgende Einschub zu 
        umfangreich ist? Ich kann ihn auch rauslassen, wenn es auch ohne 
        klar ist.</authorComment>
<%
 }
%>

Das ist nicht sehr strukturiert, da der JSP-Block endet, bevor das authorComment-Element beginnt; dann wird noch ein Block nach dem Element angehängt, der die im ersten Block geöffnete Klammer schließt. Es ist sehr leicht möglich, Code-Strukturen falsch aufeinander abzustimmen oder schließende Blöcke zu vergessen. Das XSP-Paradigma verlangt zu jedem öffnenden ein schließendes Element (die Standard-XML-Eigenschaft der Wohlgeformtheit), außerdem ist einem Element immer ein Block zugeordnet.

Mit diesen logischen Strukturen im Dokument muß die XSP-Seite nur noch die Request-Parameter interpretieren. Sie können dazu die eingebaute XSP-Variable request benutzen, die das Verhalten des javax.servlet.http.HttpServletRequest-Objekts nachbildet. Die folgenden Erweiterungen im Code lesen die Werte der Request-Variablen userRole und password (wenn sie existieren). Der Wert von userRole wird daraufhin mit den Rollen verglichen, die die Bemerkungen sehen sollen (»author« und »editor«). Wenn eine Übereinstimmung gefunden wird, wird außerdem das Paßwort überprüft. Wenn es mit dem Schlüssel für die entsprechende Rolle übereinstimmt, wird der boolean-Variable der Wert true zugewiesen und das authorComment-Element wird Teil der XML-Ausgabe:

   <xsp:logic>
    boolean authorOrEditor = false;

    // Logik zur Entscheidung ob Nutzer Autor oder Lektor ist
 <![CDATA[ String[] roleValues = request.getParameterValues("userRole"); String[] passwordValues = request.getParameterValues("password"); if ((roleValues != null) && (passwordValues != null)) {   String userRole = roleValues[0];   String password = passwordValues[0];   if (userRole.equals("author") && password.equals("brett")) {     authorOrEditor = true;   } else     if (userRole.equals("editor") && password.equals("mike")) {     authorOrEditor = true;   } } ]]>
    
    if (authorOrEditor) {
...

Beachten Sie bitte, daß ein großer Teil der Logik in ein CDATA-Tag eingeschlossen ist. XSP wird nach wie vor als XML ausgewertet und muß demzufolge den Regeln für ein XML-Dokument entsprechen; die doppelten Anführungszeichen und das »&« in den Java-Teilen sind aber in XML-Dokumenten nicht erlaubt. Anstatt diese Zeichen zu quoten und ein ziemlich seltsam aussehendes XML-Dokument zu erhalten, können Sie das CDATA-Tag benutzen und einfach normalen Java-Code schreiben. Sonst müßten Sie folgenden Code schreiben:

<xsp:logic>
 boolean authorOrEditor = false;

 String[] roleValues = 
   request.getParameterValues(&quot;userRole&quot;);
 String[] passwordValues = 
   request.getParameterValues(&quot;password&quot;);
 if ((roleValues != null) &amp;&amp; 
     (passwordValues != null)) {
   String userRole = roleValues[0];
   String password = passwordValues[0];
   if (userRole.equals("author") &amp;&amp; 
       password.equals("brett")) {
     authorOrEditor = true;
   } else
   if (userRole.equals("editor") &amp;&amp; 
       password.equals("mike")) {
     authorOrEditor = true;
   }
 }
...
</xsp:logic>

Nun können die Authentifizierungsseite und das aus dem XML generierte PDF-Dokument getestet werden. Die Ausgabe sollte ähnlich wie Abbildung 10-8 aussehen, wenn Sie mit einem Browser auf http://<hostname>:<port>/cocoon/entry.html zugreifen.

Abbildung 10-8: Startseite für chapterTen.xml als XSP-Seite
Startseite für chapterTen.xml als XSP-Seite

Sie können mittels des Paßwortes »brett« in die Rolle des Autors schlüpfen, das Paßwort für die Rolle als Lektor ist »mike«. In beiden Fällen erhalten Sie die in Abbildung 10-9 gezeigte PDF-Ausgabe.

Abbildung 10-9: XSP-Ausgabe für Autoren oder Lektoren
XSP-Ausgabe für Autoren oder Lektoren

Eine Sache, die bisher noch fehlt, ist die Trennung von Inhalt und Logik der Seite. Genau wie JSP die Benutzung von JavaBeans zur Abstraktion der Logik von Inhalt und Präsentation einer Seite gestattet, können Sie bei XSP sogenannte Tag-Libraries (Tag-Bibliotheken) erstellen. Solche Bibliotheken definieren Tags, die die Ausführung des entsprechenden Codes in der Bibliothek auslösen können.

Zusätzlich zu der Anzeige, die von der Identität des Nutzers abhängt, könnte die XSP-Seite noch anzeigen, ob sich das betrachtete Kapitel im Entwurfsstadium befindet. Dazu könnte das aktuelle Datum des Entwurfs angezeigt werden (das eingefroren wird, wenn das Kapitel komplett ist). Anstatt inline Java-Code einzufügen, soll diese Funktionalität über eine selbsterstellte Tag-Library realisiert werden. Außerdem wird ein XSP-Element kreiert, das aus der Kapitelnummer und dem Titel die fertige Überschrift formatiert. Diese Funktion wird außerdem das Datum des Entwurfs einfügen.

Um dies zu erreichen, müssen Sie zunächst eine Tag-Library erstellen, auf die die XSP-Seite zugreifen kann. Ein Großteil der Tag-Library basiert auf einem XSL-Stylesheet. Ein möglicher Ausgangspunkt dafür ist das in Beispiel 10-11 gezeigte Beispiel, welches einfach jeglichen Input unverändert weiterleitet. Dieses Skelett wird als JavaXML.xsp.xsl im Verzeichnis XSL/ gespeichert. Wichtig ist die javaxml2-Namensraum-Deklaration, die gebraucht wird, um Elemente dieses Namensraumes zu erkennen, die in XSP-Seiten verwendet werden.

Beispiel 10-11: Skelett einer XSP-Tag-Library

<?xml version="1.0"?>

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xsp="http://www.apache.org/1999/XSP/Core"
  xmlns:javaxml2="http://www.oreilly.com/javaxml2"
>
  <xsl:template match="xsp:page">
    <xsp:page>
      <xsl:copy>
        <xsl:apply-templates select="@*"/>
      </xsl:copy>

      <xsl:apply-templates/>
    </xsp:page>
  </xsl:template>

  <xsl:template match="@*|*|text()|processing-instruction(  )">
    <xsl:copy>
      <xsl:apply-templates 
           select="@*|*|text()|processing-instruction(  )"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Durch das xsp:page-Tag wird es möglich, alle Elemente innerhalb dieses Stylesheets zu behandeln. Im XSP-Sprachgebrauch heißt so etwas logicsheet. Nun kann man Java-Methoden einfügen, die die Templates dieses Logicsheets aufrufen sollen:

  <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>        private static String getDraftDate(  ) {          return (new SimpleDateFormat("MM/dd/yyyy"))            .format(new Date(  ));        }        private static String getTitle(int chapterNum,                                        String chapterTitle) {          return chapterNum + ". " + chapterTitle;        }      </xsp:logic>

      <xsl:apply-templates/>
    </xsp:page>
  </xsl:template>

Hier wurden mehrere neue XSP-Elemente eingeführt: Zunächst umschließt xsp:structure mehrere xsp:include-Anweisungen. Diese bewirken genau dasselbe wie ihr Java-Gegenstück import. Dadurch kann man die entsprechenden Java-Klassen mit den bloßen Klassennamen ansprechen und muß nicht den vollständigen Namen mit Package benutzen. Nachdem dieser Zugriff möglich ist, werden zwei Methoden definiert und implementiert: Eine, die die Kapitelüberschrift aus Kapitelnummer und -titel erzeugt, und eine zweite, die das aktuelle Datum als formatierten String liefert. Alle Elemente dieses Logicsheets können auf beide Methoden zugreifen.

Nun wird das Element spezifiziert, das angibt, wann ein XSP-Resultat ein XML-Element ersetzen soll. Der Namensraum javaxml2 ist bereits im root-Element deklariert, so daß er für die neuen Elemente in der Tag-Library verwendet werden kann. Folgendes Template kann nun in das Logicsheet eingefügt werden:

Wenn ein Dokument mit dieser Tag-Library das Element javaxml2:draftTitle verwendet (oder nur draftTitle, wenn der Standard-Namensraum auf http://www.oreilly.com/javaxml2 gesetzt ist), wird das Resultat von getTitle( ) dem Wert der Methode getDraftDate( ) vorangestellt. Das Element javaxml2:draftTitle erwartet außerdem zwei Argumente: die Nummer und den Titel des Kapitels. Der XSP-Prozessor erkennt am Einschließen des Methodenaufrufs in <xsp:expr>-Tags, daß eine definierte Methode aufgerufen werden soll. Das Einschließen des zweiten Arguments (des Titels) in Anführungszeichen zeigt an, daß es sich um einen String handelt. Da die Kapitelnummer als int behandelt werden soll, werden hier die Anführungszeichen weggelassen.

Wenn das XSP-Logicsheet (ebenfalls auf der Website des Buches erhältlich) fertiggestellt ist, müssen Sie nur noch dafür sorgen, daß Cocoon darauf zugreifen kann. Das kann man auf zwei Arten erreichen. Die erste ist, den Ort der Datei als URI anzugeben, um der Servlet-Engine (und damit Cocoon) zu erlauben, sie zu finden. Um zum Beispiel das XSP-Logicsheet mittels seiner URI zur Ressourcenliste von Cocoon hinzuzufügen, müssen Sie folgende Zeilen zu der Datei cocoon.properties auf einem Unix-basierten System hinzufügen:

# Zuordnen der Bibliotheken und der zugehörigen Namensräume.
# Syntax:
#   processor.xsp.logicsheet.<namespace-tag>.<language> = URL zur Datei
# wobei "URL zur Datei" gewöhnlich mit file:// beginnt, wenn die Library im
# lokalen Dateisystem zu finden ist
processor.xsp.logicsheet.context.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/context.xsl
processor.xsp.logicsheet.cookie.java   = 
    resource://org/apache/cocoon/processor/xsp/library/java/cookie.xsl
processor.xsp.logicsheet.global.java   = 
    resource://org/apache/cocoon/processor/xsp/library/java/global.xsl
processor.xsp.logicsheet.request.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/request.xsl
processor.xsp.logicsheet.response.java = 
    resource://org/apache/cocoon/processor/xsp/library/java/response.xsl
processor.xsp.logicsheet.session.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/session.xsl
processor.xsp.logicsheet.util.java     = 
    resource://org/apache/cocoon/processor/xsp/library/java/util.xsl
processor.xsp.logicsheet.sql.java      = 
    resource://org/apache/cocoon/processor/xsp/library/sql/sql.xsl
processor.xsp.logicsheet.esql.java     = 
    resource://org/apache/cocoon/processor/xsp/library/sql/esql.xsl
processor.xsp.logicsheet.fp.java       = 
    resource://org/apache/cocoon/processor/xsp/library/fp/fp.xsl

processor.xsp.library.JavaXML.java     =     file:///usr/local/jakarta-tomcat/webapps/cocoon/XSL/JavaXML.xsp.xsl

Für ein Windows-System wäre das:

# Zuordnen der Bibliotheken und der zugehörigen Namensräume.
# Syntax:
#   processor.xsp.logicsheet.<namespace-tag>.<language> = URL zur Datei
# wobei "URL zur Datei" gewöhnlich mit file:// beginnt, wenn die Library im
# lokalen Dateisystem zu finden ist
processor.xsp.logicsheet.context.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/context.xsl
processor.xsp.logicsheet.cookie.java   = 
    resource://org/apache/cocoon/processor/xsp/library/java/cookie.xsl
processor.xsp.logicsheet.global.java   = 
    resource://org/apache/cocoon/processor/xsp/library/java/global.xsl
processor.xsp.logicsheet.request.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/request.xsl
processor.xsp.logicsheet.response.java = 
    resource://org/apache/cocoon/processor/xsp/library/java/response.xsl
processor.xsp.logicsheet.session.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/session.xsl
processor.xsp.logicsheet.util.java     = 
    resource://org/apache/cocoon/processor/xsp/library/java/util.xsl
processor.xsp.logicsheet.sql.java      = 
    resource://org/apache/cocoon/processor/xsp/library/sql/sql.xsl
processor.xsp.logicsheet.esql.java     = 
    resource://org/apache/cocoon/processor/xsp/library/sql/esql.xsl
processor.xsp.logicsheet.fp.java       = 
    resource://org/apache/cocoon/processor/xsp/library/fp/fp.xsl

processor.xsp.library.javaxml2.java    =     file:///C:/java/jakarta-tomcat/webapps/cocoon/XSL/JavaXML.xsp.xsl

Während dieses Tag gut zum Testen geeignet ist, stellt es keine gute Lösung für die Trennung der Logicsheets von der Servlet-Engine dar und sorgt für einen ziemlichen Administrationsmehraufwand beim Hinzufügen neuer Logicsheets: Für jedes neue Logicsheet müßten Sie die Datei cocoon.properties um eine weitere Zeile erweitern.

Es ist ebenfalls möglich, der Servlet-Engine über ihren Klassenpfad eine weitere Ressource hinzuzufügen. Damit können Sie selbsterstellte Logicsheets in einer jar-Datei zusammenfassen und diese zum Klassenpfad der Servlet-Engine hinzufügen (was bei Tomcat bedeutet, sie einfach in das Verzeichnis lib/ zu kopieren!). Neue Logicsheets können einfach zu der bestehenden jar-Datei hinzugefügt werden, womit Sie eine zentrale Stelle zur Speicherung Ihrer XSP-Logicsheets geschaffen haben. Im Verzeichnis XSL/ in der Document-Root des Webservers wird die entsprechende jar-Datei wie folgt erstellt:

jar cvf logicsheets.jar JavaXML.xsp.xsl

Die entstehende Datei logicsheets.jar wird anschließend in das Verzeichnis TOMCAT_ HOME/lib/ zu den anderen Cocoon-Bibliotheken kopiert. Damit wird sichergestellt, daß Tomcat die Bibliothek beim Start lädt. Mit dem nun verfügbaren Logicsheet müssen Sie Cocoon noch wissen lassen, wo es nach Referenzen zum javaxml2-Namensraum aus den XSP-Seiten schauen soll. Dazu ist die Datei cocoon.properties zu editieren; in dem Abschnitt mit den verschiedenen XSP-Ressourcen wird die neue Referenz auf das Logicsheet eingefügt:

# Zuordnen der Bibliotheken und der zugehörigen Namensräume.
# Syntax:
#   processor.xsp.logicsheet.<namespace-tag>.<language> = URL zur Datei
# wobei "URL zur Datei" gewöhnlich mit file:// beginnt, wenn die Library im
# lokalen Dateisystem zu finden ist
processor.xsp.logicsheet.context.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/context.xsl
processor.xsp.logicsheet.cookie.java   = 
    resource://org/apache/cocoon/processor/xsp/library/java/cookie.xsl
processor.xsp.logicsheet.global.java   = 
    resource://org/apache/cocoon/processor/xsp/library/java/global.xsl
processor.xsp.logicsheet.request.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/request.xsl
processor.xsp.logicsheet.response.java = 
    resource://org/apache/cocoon/processor/xsp/library/java/response.xsl
processor.xsp.logicsheet.session.java  = 
    resource://org/apache/cocoon/processor/xsp/library/java/session.xsl
processor.xsp.logicsheet.util.java     = 
    resource://org/apache/cocoon/processor/xsp/library/java/util.xsl
processor.xsp.logicsheet.sql.java      = 
    resource://org/apache/cocoon/processor/xsp/library/sql/sql.xsl
processor.xsp.logicsheet.esql.java     = 
    resource://org/apache/cocoon/processor/xsp/library/sql/esql.xsl
processor.xsp.logicsheet.fp.java       = 
    resource://org/apache/cocoon/processor/xsp/library/fp/fp.xsl

processor.xsp.logicsheet.javaxml2.java = resource://JavaXML.xsp.xsl

Da sich das Logicsheet innerhalb der Datei logicsheets.jar nicht in irgendwelchen Unterverzeichnissen befindet, kann man einfach den Namen des Logicsheets als Pfad der Ressource verwenden. Nunmehr muß die Servlet-Engine noch neu gestartet werden (womit Sie gleichzeitig sicherstellen, daß die neue Tag-Library auch geladen wird). Das lädt auch die Datei cocoon.properties neu und damit steht das Logicsheet zur Verwendung bereit. Da die Cocoon-Engine zur Behandlung von Requests benutzt wird, hat jede XSP-Seite, die die Benutzung des javaxml2-Namensraums deklariert, Zugriff auf das Logicsheet, das als javaxml2-Library spezifiziert wurde. Daher muß der XSP-Seite noch eine Namensraum-Deklaration für den Namensraum javaxml2 hinzugefügt werden:

<?xml version="1.0"?>

<?cocoon-process type="xsp"?>
<?cocoon-process type="xslt"?>
<?xml-stylesheet href="XSL/JavaXML.fo.xsl" type="text/xsl"?>

<xsp:page language="java"
          xmlns:xsp="http://www.apache.org/1999/XSP/Core"
          xmlns:javaxml2="http://www.oreilly.com/javaxml2"
>
<book>
  <!-- Book content -->
</book>
</xsp:page>

Da die Tag-Library jetzt benutzt werden kann, kann das neue Element javaxml2:draftTitle im XML-Dokument chapterTen.xml verwendet werden:

<contents>
  <chapter title="Web Publishing Frameworks" number="10">
    <javaxml2:draftTitle chapterNum="10"                         chapterTitle="Web Publishing Framework" />
...

Sie müssen dazu die normale Kapitelüberschrift durch das in der XSP-Tag-Library definierte Element ersetzen und dazu die folgende Änderung in der Stylesheet-Datei JavaXML.fo.xsl vornehmen:

  <xsl:template match="chapter">
    <fo:block font-size="24pt" 
              text-align-last="center" 
              space-before.optimum="24pt">
<!--                    <xsl:value-of select="@number" />.      <xsl:value-of select="@title" />-->      
      <xsl:apply-templates/>
    </fo:block>
  </xsl:template>

Das sollte die Überschrift mit der Kapitelnummer, dem Titel und dem Datum des Entwurfs ergeben. Wenn Sie auf diese neue Version der XSP-Seite zugreifen, erhalten Sie das in Abbildung 10-10 gezeigte Ergebnis.

Abbildung 10-10: Ausgabe bei Benutzung der XSP-Tag-Library
Ausgabe bei Benutzung der XSP-Tag-Library

Hier wurde nur an der Oberfläche von XSP gekratzt. Bereits dieses einfache Beispiel erlaubt es, die Überschrift durch bloße Änderungen des Logicsheets und ohne Änderungen an Präsentation oder Inhalt in eine völlig andere Form zu bringen, wenn das Kapitel abgeschlossen ist.

Auf die gleiche Art erlaubt es XSP, sehr strikte Übereinkünfte zur Trennung der Präsentation von der Logik und vom Inhalt zu kreieren. Das Hinzufügen serverseitiger Komponenten, wie zum Beispiel Enterprise JavaBeans, kann Geschäftslogik mit ins Boot holen. Anders als die Benutzung einer weniger flexiblen Lösung wie JSP, die mit HTML an ein Präsentationsformat gekoppelt ist, erlaubt es die Benutzung von XSP, die Komponenten weniger eng zu koppeln, und ist damit eine bessere Lösung zur Applikationsentwicklung. XSP verspricht außerdem, einer der zentralen Punkte in Cocoon 2.0 zu werden, auf das ich als nächstes einen Blick werfen werde.

Cocoon 2.0 und darüber hinaus

Cocoon 2.0 als nächste Generation von Cocoon verspricht für Web Publishing Frameworks einen riesigen Schritt vorwärts. Cocoon 1.x, das im wesentlichen auf der Transformation von XML mittels XSL beruht, weist noch gravierende Einschränkungen auf. Erstens reduziert es die Kosten der Administration und Pflege großer Sites nicht wesentlich.

Während ein Dokument in viele verschiedene Client-Ansichten umgewandelt werden kann, existiert dennoch eine große Anzahl an Dokumenten. Generell resultieren daraus entweder lange URIs (wie zum Beispiel /content/publishing/books/javaxml/contents.xml), eine große Anzahl virtueller Mappings (/javaxml zu /content/publishing/ books/javaxml) oder eine Kombination der beiden. Zusätzlich ist eine strikte Trennung der Präsentation, der Logik und des Inhalts untereinander schwierig zu erreichen und noch schwieriger aufrechtzuerhalten.

Cocoon 2 konzentriert sich auf die Kontrakte zwischen diesen drei Schichten und versucht dadurch, die Kosten des Managements niedrig zu halten. XSP ist der Mittelpunkt dieses Designs. Weiterhin wird versucht, durch das Konzept der Sitemap die Trennung zwischen XSP-, XML- und statischen HTML-Seiten vor dem neugierigen Nutzer zu verbergen. Weiterhin werden fortgeschrittene Überlegungen zur Vorkompilierung und zum Speicherverbrauch dazu beitragen, daß sich Cocoon 2.0 mehr von Cocoon 1.x abhebt als Cocoon 1.x von einem Standard-Webserver.

Eine bedeutende Änderung in Cocoon 2 ist, daß es nicht mehr länger ein einfaches Mapping für XML-Dokumente verlangt. Obwohl das in der Version 1.x gut funktioniert, überläßt es doch das Management der Nicht-XML-Dokumente dem Web-Master. Das ist möglicherweise eine ganz andere Person als derjenige, der für die XML-Dokumente verantwortlich ist.

Cocoon 2 versucht nun, das Management der gesamten Webseite zu übernehmen. Aus diesem Grunde ist das Haupt-Cocoon-Servlet (org.apache.cocoon. servlet.CocoonServlet in der Version 2.0) generell auf eine URI, wie zum Beispiel /Cocoon, gemappt. Es könnte aber auch zur völligen Kontrolle der Site auf die Wurzel des Webservers selbst gemappt sein (einfach »/«). Eine angeforderte URL folgt dann dem Servlet-Mapping: zum Beispiel http://myHost.com/Cocoon/myPage.xml oder http://my Host.com/Cocoon/myDynamicPage.xsp.

Mit diesem Mapping können nun statische HTML-Dokumente mit XML-Dokumenten gemischt werden, was das Management aller Dateien auf dem Server durch eine Person oder Gruppe erlaubt. Wenn HTML-, WML- und XML-Dateien in einem Verzeichnis gemischt werden müssen, muß daraus nicht zwangsläufig Verwirrung resultieren, und es können gleichartige URIs benutzt werden. Cocoon 2.0 wird HTML wie jedes andere Format gleichermaßen gern ausliefern; mit einem Mapping der Wurzel des Servers auf Cocoon wird das Web Publishing Framework für den Nutzer unsichtbar.

Eine weitere wichtige Neuerung in Cocoon 2.0 ist die Sitemap. In Cocoon bietet die Sitemap eine zentrale Anlaufstelle zur Administration einer Website. Cocoon benutzt die Sitemap, um zu entscheiden, wie die eingehenden URIs bearbeitet werden sollen. Der Request http://myCocoonSite.com/Cocoon/javaxml/chapterOne.html zum Beispiel wird vom Cocoon-Servlet zerlegt; die Zerlegung ergibt, daß die eigentlich angeforderte URI /javaxml/chapterOne.html ist. Es könnte jedoch sein, daß die Datei chapterOne.html keine statische HTML-Datei sein soll, sondern aus der Transformation eines XML-Dokuments gewonnen werden soll (wie in den vorangehenden Beispielen). Mittels einer Sitemap wird das ziemlich einfach! Beispiel 10-12 zeigt das entsprechende Vorgehen.

Beispiel 10-12: Beispiel einer Cocoon 2-Sitemap

  <sitemap>
   <process match="/javaxml/*.html">
    <generator type="file" src="/docs/javaxml/*.xml"
    <filter type="xslt">
     <parameter name="stylesheet" value="/styles/JavaXML.html.xsl"/>
    </filter>
    <serializer type="html"/>
   </process>

   <process match="/javaxml/*.pdf">
    <generator type="file" src="/docs/javaxml/*.xml"
    <filter type="xslt">
     <parameter name="stylesheet" value="/styles/JavaXML.pdf.xsl"/>
    </filter>
    <serializer type="fop"/>
   </process>
  </sitemap>

In diesem Beispiel paßt die URI /javaxml/chapterOne.html auf die Sitemap-Direktive /javaxml/*.html. Sie bestimmt, daß es sich dabei um eine reale Datei handelt und daß die Quelldatei über das Mapping /docs/javaxml/*. xml gefunden wird, was /docs/javaxml/ chapterOne.xml (den Namen der Datei, die transformiert werden soll) ergibt. Dann wird der XSLT-Filter angewendet; das zu benutzende Stylesheet JavaXML.html.xsl wird ebenfalls durch die Sitemap bestimmt. Das Resultat der Transformation wird danach dem Nutzer gezeigt. Zusätzlich könnte die XML-Datei aus einer vorher verarbeiteten XSP-Datei erzeugt worden sein, die nach XML konvertiert und dann formatiert wird.

Der gleiche Prozeß kann ein PDF mit nur ein paar zusätzlichen Zeilen in der SiteMap (wie im vorangehenden Beispiel gezeigt) aus dem Request http://myCocoonSite.com/Cocoon/javaxml/chapterOne.pdf erzeugen. Eine deutliche Änderung gegenüber Cocoon 1.x ist, daß die Verarbeitungsanweisungen komplett aus den einzelnen XML-Dokumenten entfernt werden können. Die gleichartige Anwendung von Stylesheets und Verarbeitung kann basierend auf dem jeweiligen Verzeichnis erfolgen. Das Erzeugen eines XML-Dokuments im Verzeichnis /docs/javaxml/ sorgt dafür, daß das Dokument als HTML- und als PDF-Version benutzt werden kann. Es ist extrem einfach, das Stylesheet für alle Dokumente zu ändern, was unter Cocoon 1.x eine schwierige und langwierige Aufgabe ist. Anstatt eine Änderung in jedem XML-Dokument vornehmen zu müssen, muß man lediglich eine Zeile in der Sitemap ändern.

Die Cocoon-Sitemap wird noch entwickelt und in ihrer endgültigen Fassung sicher einige weitere Verbesserungen und Änderungen an ihrer Struktur und ihrem Format erfahren. Um daran teilzuhaben, können Sie die Mailing-Listen cocoon-users@xml.apache.org und cocoon-dev@xml.apache.org abonnieren. Das Apache-Projekt unter http://xml.apache.org enthält Informationen über die Mitgliedschaft in diesen Listen und über die Teilnahme am Cocoon-Projekt.

Eine letzte Verbesserung, die Cocoon 2 bringen wird, sind vorkompilierte und Event-basierte Producers und Prozessoren. In Cocoon ist ein Producer für die Transformation einer Request-URI in einen XML-Dokument-Stream verantwortlich. Ein Prozessor nimmt einen solchen Stream (im Moment das XML-Dokument in einem DOM-Baum) und macht daraus vom Client lesbaren Output. Die Producers und Prozessoren wurden im Abschnitt über Cocoon 1.x nicht behandelt, da sie sich in der Version 2 drastisch ändern werden; etwa schon bestehende werden dann höchstwahrscheinlich nutzlos sein und umgeschrieben werden müssen.

Cocoon 2 wird sich dafür von DOM mehr in Richtung Event-basiertes SAX bewegen, das in eine DOM-Struktur verpackt wird. Da ein Producer unter Cocoon 1.x ein XML-Dokument im Speicher erstellen mußte, konnte die resultierende DOM-Struktur extrem groß werden. Dies führte zu Engpässen bei Systemressourcen, speziell bei komplexen Aufgaben wie großen Transformationen oder der Verarbeitung von Formatting Objects (Erzeugung von PDF). Aus diesem Grund wird DOM in Cocoon 2 einen einfachen Wrapper um SAX-basierte Events bilden und damit schlanke und einfache Producers und Prozessoren ermöglichen.

Zusätzlich werden Producers und Prozessoren vorkompilierte Varianten anderer Formate sein. Zum Beispiel könnten vorkompilierte XSL-Stylesheets Prozessoren und vorkompilierte XSP-Seiten Producers sein. Damit wird die Performance weiter gesteigert und Last vom Client genommen. Diese und andere Änderungen benutzen weiterhin ein Komponentenmodell und machen Cocoon damit zu einem sehr flexiblen und erweiterbaren Framework. Um über die neuesten Fortschritte informiert zu sein, sollten Sie die Cocoon-Website im Auge behalten.

Und was kommt jetzt?

Das nächste Kapitel beschäftigt sich mit einer Technologie, die es erlaubt, XML als Datenformat in einem wichtigen Anfrage/Antwort-Modell zu nutzen: XML Remote Procedure Calls. XML-RPC erlaubt es Clients in einem verteilten System, die Ausführung von Aufgaben auf einem Server in einem anderen Teil des Netzwerkes anzufordern. Bis vor kurzem sank die Popularität von RPC ständig weiter ab, hauptsächlich weil sich die RMI-basierten Technologien im Java-Umfeld (hervorzuheben sind hier EJBs) rasant verbreiten. Dennoch ist XML-RPC mit XML als Datenformat eine neue Lösung für viele Probleme, die nicht sauber oder effizient ohne RPC gelöst werden könnten. Auf XML-RPC und speziell die Java-Implementierung dieser Technik wird als nächstes eingegangen.

1)
»HTML und WML« umfassen ebenfalls die unterstützenden Techniken für die jeweilige Sprache. Diese Techniken, wie zum Beispiel Flash oder Shockwave, sind in Ihrer Handhabung nicht einfach – ich will auf keinen Fall Autoren geringschätzen, die sich damit beschäftigen.
2)
Aufmerksamen Lesern wird das Fehlen von Referenzen auf phone.com auffallen; der Grund dafür ist, daß phone.com nun Teil von OpenWave ist, siehe auch http://www.openwave.com.
3)
Das ist eine drastische Vereinfachung; eine JSP wird in Wahrheit in ein Servlet vorkompiliert und ein PrintWriter sorgt für die Ausgabe. Weitere Informationen über JSP finden Sie zum Beispiel in JavaServer Pages von Hans Bergsten (O’Reilly Verlag).