Das Cocoon Tutorial

Stephan Niedermeier

Es ist nicht erlaubt, dieses Tutorial oder Teile davon ohne Einverständis des Autors zu vervielfältigen und weiterzugeben, in welcher Form auch immer. Die Vervielfältigung des Ganzen oder Teilen daraus ist jedoch für öffentliche Schulen, Universitäten und andere gemeinnützige Einrichtungen erlaubt, solange die Vervielfältigung ausschließlich kostenlosen Lehrzwecken dient und auf die Herkunft der Auszüge hingewiesen wird. Weblinks auf dieses Tutorial sind ausdrücklich erlaubt.


Table of Contents

Vorwort
1. Die Applikation Cocoon
1. Was ist Cocoon?
2. Cocoon besorgen
3. Cocoon kompilieren
4. Cocoon installieren
2. XML - Das unabhängige Dateiformat
1. Der Aufbau eines XML-Dokuments
2. XML-Dokumente beschränken
3. XSL - Ein XML-Dokument umwandeln
4. Von XML zu XHTML
3. Java - Die unabhängige Programmiersprache
4. Die Sitemap
1. Die Komponenten
1.1. Die Logik-Komponenten
1.1.1. Die Matcher
1.1.2. Die Selectoren
1.1.3. Die Actions
1.2. Die Bearbeitungs-Komponenten
1.2.1. Der SAX-Stream
1.2.2. Die Generatoren
1.2.3. Die Transformatoren
1.2.4. Die Serializer
1.2.5. Die Reader
2. Die Gruppierungen
2.1. Die Resourcen
2.2. Die Views
2.3. Die Action-Sets
3. Die Pipelines
5. Control Flow
6. XSP - Extensible Server Page
7. Tutorial 1 - "Hello world!"
1. Erstellen einer Sub-Applikation
2. Erstellen der XML-Datei
3. Erstellen des XSLT-Stylesheets
4. Die Sitemap anpassen
8. Tutorial 2 - Ein einfaches Formular
1. Aktivieren der Verarbeitung von Request-Parametern
2. Erstellen der XML- und XSLT-Datei
3. Erstellen der Pipeline
9. Tutorial 3 - Logik mit Hilfe von XSP integrieren
1. Erstellen der notwendigen Ressourcen
2. XSP-Logik integrieren
3. Registrieren in der Sitemap
10. Tutorial 4 - Eine eigene Action programmieren
1. Erstellen der Action-Klasse
2. Erstellen des Ausgabedokuments
3. Registrieren und Ausführen der Action

Vorwort

Nun ist es schon knapp 2 Jahre online das Cocoon-Tutorial und Gott sei dank hat sich seit damals eine Menge in der Cocoon-Community getan. Nicht nur dass Cocoon ein eigenes Apache Top-Level-Projekt geworden ist, nein auch die Anwendung selbst hat sich zu einem Umfang gemausert, der nur schwer von anderen Frameworks zu toppen ist. An diesem Punkt möchte ich als kleine Auswahl stellvertretend die Control-Flow-Technik, Cocoon-Forms, das Portal-Framework oder den Scheduler-Block als Bestandteile nennen, die seit der Version 2.1 neu hinzu gekommen sind und mich persönlich immer wieder in erstaunen versetzen, welches Know-How hinter diesen und anderen Dingen steckt.

Doch nicht nur die Cocoon-Entwickler waren fleißig, nein auch ich habe die Zeit genutzt und an diesem Tutorial gebastelt und es an die aktuelle Version von Cocoon angepasst. Dabei habe ich einige Teile im Vergleich zum "alten" Tutorial weggelassen. Sollte Ihrer Meinung nach etwas wichtiges fehlen, so lassen Sie es mich bitte wissen. Ich habe mich dazu entschlossen, auch diese Version wieder als All-In-One-Page anzubieten. Ich erhielt aber bereits zahlreiche Emails mit der Frage, ob man das Tutorial nicht in eine HTML-Seite pro Kapitel aufteilen könnte. Sicherlich, man kann. Leider erhielt ich aber auch fast genauso viele Emails deren Absender ansprachen, dass Ihnen die jetztige AIOP sehr gut gefällt. Aus diesem Grund habe ich eine Abstimmung im Cocoonforum eingerichtet unter der jeder wählen kann, welche Art des Tutorials er bevorzugt. Ich werde diese Umfrage ca. 2 Monate laufen lassen und anschließend anhand der Abstimmungen entscheiden, welche Version letztendlich verwendet wird. Also machen Sie mit: Zur Abstimmung.

Auch diesmal gibt es wieder einen Link, über den man Fehler im Tutorial melden kann. Diesmal werden diese aber nicht an mich per Email gesendet, sondern Sie können diese direkt in das Forum als neuen Beitrag eintragen. Wenn Sie möchten, sogar anonym. Dies hat den großen Vorteil, dass auch andere direkt auf die Fehler hingwiesen werden, auch wenn diese noch gar nicht beseitigt sind. Bitte verwenden Sie diese Möglichkeit, falls Sie meinen, einen Fehler entdeckt zu haben. Vielen Dank!

An dieser Stelle möchte ich mich für die zahlreichen Fehlermeldungen bedanken, die ich zum "alten" Tutorial erhalten habe. Einige Leser haben regelrecht das ganze Tutorial auseinander genommen und mir wirklich jeden, auch noch so kleinen Fehler gemeldet. Das hat mich natürlich sehr gefreut! Vielen Dank. Leider konnte ich aus technischen Gründen nicht alle Berichtigungen mit in die neue Version übernehmen.

Dem jedoch nicht genug, zusätzlich habe ich mir die Zeit genommen und ein Buch über Cocoon geschrieben in dem Sie nun alles wissenswerte über Cocoon schwarz auf weiß nachlesen können. Der Titel dieses Buches, wie könnte es anders sein: "Cocoon 2 und Tomcat". Auf geballten 800 Seiten finden Sie alles was Sie über Cocoon und den Servlet-Container wissen sollten und ein wenig mehr. Mehr Informationen zu diesem Buch können Sie hier erhalten: http://www.cocoonbuch.de

Figure 1. Cocoon 2 und Tomcat

Cocoon 2 und Tomcat

Doch warum eigentlich ein solches Buch, wenn es ja dieses Tutorial gibt? Ganz einfach: Dieses Tutorial soll Sie überisichtlich und auf den Punkt gebracht genau an die wichtigsten Punkte heranführen, um mit Cocoon einen schnellen Einstieg zu finden und die ersten Schritte machen zu können. Falls Sie dann vorhaben, tiefer in das System vorzudringen, kann Ihnen dieses Buch ein treuer Begleiter bei Ihren durchprogrammierten Nächten werden und Ihnen eine menge Recherchearbeit ersparen! Da soll noch nochmal einer sagen, es existiert keine Dokumentation für Cocoon ;-) Und falls Sie trotz dem Tutorial, dem Buch, den zahlreichen Webpages zum Thema und vielen Beispielen in der Distribution immer noch Fragen haben sollten, sollten Sie mal auf dem Cocoon-Forum vorbei surfen: http://www.cocoonforum.de.

Für professionelle Beratung, Planung und Realisierung rund um Cocoon kann ich Ihnen letztendlich auch meine eigenen Dienste anbieten. Kontaktieren Sie mich hierzu einfach! Ich freue mich, wenn ich mein Wissen weitergeben darf ;-)

Chapter 1. Die Applikation Cocoon

Fehler in diesem Kapitel melden. Danke!

1. Was ist Cocoon?

Cocoon ist in erster Linie ein XML-Publishing System, das von der Open Source Gemeinde Apache verwaltet wird. Es ist in der Lage, aus einem oder mehreren XML-Dokument(en) und dem zugehörigen XSL-Dokument(en) ein beliebiges Ausgabeformat zu produzieren und an beliebige Endgeräte zu versenden. Da XML/XSL basierte Lösungen immer mehr Zuspruch finden, jedoch die meisten Endgeräte noch nicht in der Lage sind, diese Formate zu lesen, dient Cocoon als "Übersetzer" in die jeweilige "Sprache" des Empfängers. Cocoon ist z.B. sogar in der Lage, das Gerät, das Daten anfordert, zu erkennen und ihm das passende Dokument zu generieren und anschliessend zuzusenden. Als Ausgabeformate seien an dieser Stelle z.B. HTML, WAP, PDF, oder RTF aufgelistet, um nur einige zu nennen.

Cocoon trennt Daten, Layout und Logik. Dieses Konzept wird in der modernen Softwarenetwicklung schon seit einiger Zeit erfolgreich eingesetzt und ist allgemein als MVC (Model View Controller) Architektur bekannt. Dadurch ist es möglich, dass die verschiedenen Entwickler getrennt an ein und demselben Projekt arbeiten können. Desweiteren wird die Wartung der erstellten Applikation wesentlich vereinfacht und in den meisten Fällen gewollte Abstraktionsebenen geschaffen. Durch die komponentenbasierte Architektur ist ein Höchstmaß an Wiederverwendbarkeit der einzelnen Komponenten -garantiert. Diese Architektur geht weit über die Möglichkeiten, die MVC selbst bietet, hinaus.

In den meisten Fällen wird Cocoon als dynamischer Website-Generator verwendet. Die Schnittstelle zwischen Cocoon und dem Web bildet hier ein reguläres Servlet. Aus diesem Grund wird Cocoon in diesem Fall fast ausnahmslos in einem sogenannten Servlet-Container, wie beispielsweise Tomcat oder Jetty betrieben. Cocoon ist aber keineswegs nur im Webumfeld zu gebrauchen. Es kann durchaus auch in lokalen Applikationen eingesetzt werden. Die mit Abstand häufigste Art und Weise, wie Cocoon betrieben wird, ist allerdings die als Web-Framework innerhalb eines Servlet-Containers.

2. Cocoon besorgen

Die stets aktuellste Version von Cocoon können Sie sich von folgender URI downloaden: http://cocoon.apache.org/mirror.cgi Das Package sollte eine Größe von etwa 45 MB besitzen. Entpacken Sie es anschließend in ein Verzeichnis Ihrer Wahl.

3. Cocoon kompilieren

Wie Sie vielleicht bereits festgestellt haben, wird Cocoon ausschließlich als Source-Distribution ausgeliefert. D.h., Sie müssen das System zuerst kompilieren, bevor Sie es verwenden können. Die Entwickler haben sich ab Version 2.1 aus einem ganz einfachen Grund zu diesem Schritt entschlossen: Cocoon besteht aus dem Core und den sogenannten Blocks. Der Core ist praktisch die Kernanwendung "Cocoon" und besteht aus allen Klassen und Dateien, die für die Inbetriebnahme von Cocoon notwendig sind. Zusätzlich zum Core können nun einzelne Zusatzmodule zusammen mit Cocoon betrieben werden. Dazu zählt z.B. ein Portal-Framework, ein Formular-Framework, verschiedene Schnittstelllen und vieles, vieles mehr. Da es jedoch häufig der Fall ist, dass für das Betreiben eines solchen Moduls ettliche Konfigurationen vorgenommen und/oder Klassen installiert werden müssen, sind die Entwickler den benutzerfreundlichen Weg gegangen und bieten die einzelnen Blocks als optionale Erweiterungen an. Der Benutzer muss vor dem kompilieren lediglich in einer Textdatei auswählen, welche Blocks er gerne integriert hätte. Somit erhält der Benutzer letzendlich eine vollständlig auf seine Bedürfnisse zugeschnitte Cocoon-Version ohne die Module, die nicht benötigt werden. Dies macht das System um einiges übersichtlicher und in vielen Fällen auch performanter.

Falls Sie eine natürliche Abneigung gegen das Kompilieren haben und sich eventuell schon ausmalen, welche Module denn der Kompiler wahrscheinlich anmeckern wird, weil er sie nicht findet, so kann ich Sie beruhigen: Cocoon wird zum einem mit dem Build-Tool Ant kompiliert und enthält zum anderen bereits alle Sourcen externer Module, die für das Kompilieren erforderlich sind. Im besten Fall müssen Sie nur die Datei build.bat bzw. build.sh starten und der Rest geschieht wie von selbst.

Hier nun kurz im Überblick die einzelnen Schritte, die für das Kompilieren erforderlich sind:

  1. Entpacken des Packages in ein Verzeichnis Ihrer Wahl, falls noch nicht geschehen. Falls Sie Cocoon mit all seinen Features einfach mal ausprobieren möchten, können Sie die nächsten Schritte überspringen und direkt zu Schritt 5 gehen.

  2. Erstellen Sie eine Kopie der Datei blocks.properties und benennen Sie diese Kopie um in local.blocks.properties.

  3. Öffnen Sie die Datei local.blocks.properties und deaktivieren Sie diejenigen Blocks, welche Sie nicht benötigen, indem Sie diejenigen Kommentare vor den entsprechenden exclude-Einträgen entfernen. Achten Sie jedoch unbedingt auf Abhängigkeiten zwischen den einzelnen Blocks, die in der Datei entsprechend vermerkt sind. Eine mehr oder weniger vollsändige Beschreibung der einzelnen Blocks können Sie auf der folgenden Apache-Website erhalten: http://wiki.apache.org/cocoon/BlockDescriptions

  4. Weitere Einstellungen können in der Datei build.properties getätigt werden. Hier können Sie z.B. festlegen, ob die zugehörige Dokumentation erzeugt oder die Beispiele eingebunden werden sollen. Auch von dieser Datei sollten Sie vor dem Editieren eine Kopie mit dem Namen local.build.properties erzeugen und die Änderungen nur an der Kopie vornehmen.

  5. Durch den Aufruf des Skripts build.sh unter Linux bzw. build.bat unter Windows wird Cocoon mit den ausgewählten Blocks kompiliert und das Ergebnis anschließend im Verzeichnis build abgelegt. Falls Sie keine Anpassung an den zuvor beschriebenen Property-Dateien gemacht haben, wird Cocoon standardmäßig mit allen sinnvollen Blocks, sowie einer Umfangreichen Beispielsammlung kompiliert.

4. Cocoon installieren

Nachdem Sie Cocoon erfolgreich kompiliert haben, geht es nun darum, das System innerhalb eines Servlet-Containers in Betrieb zu nehmen. Vorraussetzung ist allerdings, dass Sie bereits einen soclhen Servlet-Container auf Ihrem Betriebssystem erfolgreich installiert haben. Laden Sie sich hierzu den Servlet-Container Tomcat und installieren Sie diesen, wie auf der Projekt-Homepage beschrieben wurde.

Die Installation von Cocoon selbst hört sich zunächst schwieriger an als es ist, denn eigentlich ist es mit dem Kopieren des Verzeichnisses webapp innerhalb von build nach webapps des Servlet-Containers, sowie dem anschließenden Umbenennen des Verzeichnisses webapp in cocoon getan. In manchen Fällen kann es sein, dass Sie den Servlet-Container eventuell neu starten müssen. Aber direkt danach besitzen Sie bereits eine voll einsatzfähige Cocoon-Installation. Ob Ihre Cocoon-Installation funktioniert, können Sie testen, indem Sie - z.B. unter Tomcat - die URL http://localhost:8080/cocoon aufrufen. Anschließend sollten Sie die Willkommensseite Ihrer Cocoon-Installation angezeigt bekommen. Probieren Sie nun eventuell die zahlreichen Beispiele aus, die Ihnen aber nur einen kleinen Eindruck von dem vermitteln können, was Cocoon zu leisten vermag.

Denken Sie daran, dass die Portangabe 8080 von Servlet-Container zu Servlet-Container verschieden sein kann. Über welchen Port Sie Ihren Servlet-Container ansprechen können, erfahren Sie in dessen Dokumentation. Im Rest dieses Tutorials wird immer auf den Servlet-Container Tomcat bezug genommen.

Herzlichen Glückwunsch zu Ihrer Cocoon-Installation!

Chapter 2. XML - Das unabhängige Dateiformat

Fehler in diesem Kapitel melden. Danke!

Selten hat so eine einfache Sache so eine enorme Erleichterung bei Programmierern und Programmbenutzern gleichermassen gebracht, wie die Einführung von XML (Extensible Markup Language). Dieses Kapitel soll lediglich einen kleinen Überblick über XML geben. XML und seine Mechanismen ausführlich zu beschreiben, würde den Rahmen dieses Tutorials bei weitem sprengen. Ich empfehle deshalb unbedingt ein einführendes Buch zu XML durchzuarbeiten, um zumindest die grundlegenden Konzepte - die hinter XML & Co. stecken - kennenzulernen.

Der Standard zu XML 1.0 wurde 1998 vom W3C als direkter Nachfolger des schwerfälligen SGML beschlossen. Hiermit wurde ein Standard für eine leicht zu erlernende Sprache festgelegt, die im - vom Menschen - lesbaren Format vorliegt und andere Sprachen definieren kann. So kann XML z.B. die Sprache HTML definieren, aber nicht umgekehrt.

Aufgrund des offenen Dateiformates ist nicht nur jeder Mensch, sondern auch jedes beliebige Programm in der Lage, ein XML-Dokument zu interpretieren, was bei verschiedenen anderen Formaten nicht selbstverständlich ist. Da der Standard XML weltweit eindeutig ist und es im Textformat vorliegt, kann auch jedes beliebige System diese Datei interpretieren. Ob dies nun das Betriebssystem Windows, Linux oder gar der Microchip in der neuen Armbanduhr ist. Es muss keine Umwandlung des Formates erfolgen. Unabhängigkeit garantiert.

1. Der Aufbau eines XML-Dokuments

Ein Dokument ist genau dann ein XML-Dokument, wenn es mindestens die nachfolgenden Eigenschaften aufweist:

  • Es muss wohlgeformt sein

  • Es sollte eine XML-Deklaration zu Beginn besitzen. Z.B.: <?xml version="1.0"?>

Die XML-Deklaration <?xml version="1.0"?> gibt an, das es sich nachfolgend um ein XML-Dokument handelt, das der XML-Spezifikation der Version 1.0 folgt. Zusätzlich kann in der XML-Deklaration - neben anderen Informationen - auch das Encoding festgelegt werden, das beschreibt, welcher Zeichensatz für das Interpretieren des Inhalts verwendet werden muss. Häufig verwendete Zeichensätze sind beispielsweise ISO-8859-1 für westeuropäische Sprachen oder UFT-8 für Unicode. Eine entsprechende XML-Deklaration könnte dementsprechend so aussehen:<?xml version="1.0" encoding="ISO-8859-1"?>. Achten Sie allerdings unbeding darauf, dass die XML-Deklaration unmittelbar am am Anfang des Dokuments stehen muss. Es dürfen also keinerlei Zeichen (auch keine Leerzeichen!) vor dieser Deklaration stehen.

Note

Viele XML-Parser verarbeiten zwar auch XML-Dokumente, auch wenn diese keine XML-Deklaration besitzen. Ich empfehle Ihnen jedoch, unbedingt in jedem XML-Dokument eine solche Deklaration zu setzen, um spätere Fehlersuchen zu vermeiden.

Ein weiterer wichtiger Punkt ist, dass ein XML-Dokument unbedingt wohlgeformt sein muss. Darunter versteht man, dass alle Elemente innerhalb eines einzigen Root-Elementes erscheinen müssen. Zudem muss jedes öffnende Element <...> auch wieder geschlossen werden </...>.

Note

Es gibt Elemente mit und ohne Body. Für Elemente, die keinen Body besitzen, kann die Kurzschreibweise <irgendwas/> anstatt der Langform <irgendwas></irgendwas> angewendet werden. Achten Sie darauf, wenn Sie das nächste mal z.B. die Datei web.xml oder sitemap.xmap durchsehen. Beachten Sie unbedingt, dass in der Kurzform der Slash / am Ende des Tags gesetzt wird. In der Langform hingegen wird er im abschließenden Tag an den Anfang des Tags gesetzt.

Nachfolgend erhalten Sie einige Beispiele für gültige, als auch ungültige XML-Dokumente.

<?xml version="1.0"?>
<person/>

Bei diesem Beispiel handelt es sich um ein durchaus gültiges XML-Dokument. Es besitzt die einleitende XML-Deklaration, sowie ein Root-Element. Ob dieses Dokument aber viel Sinn machen würde, lassen wir mal dahingestellt.

<?xml version="1.0"?>
<person>
<vorname>Max</vorname>
<nachname>Meier</nachname>

Dieses Dokument hingegen ist nicht wohlgeformt und wird somit von keinem Programm - das wohlgeformtes XML erwartet - ohne Fehlermeldung bearbeitet werden. Denken Sie daran: Jedes öffnende Tag benötigt ein schließendes Tag. In diesem Fall fehlt also das schließende Tag </person>.

<?xml version="1.0"?>
<person>
   <vorname>Max</vorname>
   <nachname>Meier</nachname>
</person>
<person>
   <vorname>Tanja</vorname>
   <nachname>Huber</nachname>
</person>

Dieses Dokument sieht ja ganz brauchbar aus. Leider wird auch hier der XML-Parser eine Fehlermeldung bringen und die Abarbeitung einstellen, denn auch dieses Dokument ist nicht wohlgeformt. Jedes XML-Dokument darf nur ein einziges Root-Element (=Wurzelelement) besitzen. In diesem Fall existieren jedoch zwei Elemente <person> in der ersten Ebene. Dies können wir umgehen, indem wir die beiden Personendaten in ein einziges Root-Element <personen> stecken:

<?xml version="1.0"?>
<personen>
   <person>
      <vorname>Max</vorname>
      <nachname>Meier</nachname>
   </person>
   <person>
      <vorname>Tanja</vorname>
      <nachname>Huber</nachname>
   </person>
</personen>

2. XML-Dokumente beschränken

XML ist eine Meta- oder Auszeichnungssprache. D.h., es beschreibt seinen Inhalt ohne ihn zu verändern. Wer sich bereits ein wenig mit der Erstellung von Websites befasst hat, ist auch hier mit Sicherheit bereits auf eine bekannte Metasprache gestossen: HTML. Der Unterschied von HTML zu XML ist nicht gross, aber der entscheidende Punkt. Während HTML einen festgelegten Umfang an Tags bzw. Elemente beinhaltet (z.B. <p>, <b>, ...) und ausschließlich diese gegebenen Tags interpretiert, können die Elemente von XML frei nach Belieben definiert und somit den eigenen Bedürfnissen angepasst werden. Die Definition der Elemente von HTML sind im Parser des jeweiligen Browsers integriert, also mehr oder weniger fest codiert. Anders bei XML: Hier wird die Definition der Elemente in der sogenannten DTD (Document Type Definition) oder in XML-Schema vorgenommen. In diesen Definitionen werden - unter anderem - festgelegt, wie die Elemente benannt sein müssen, welche Attribute sie besitzen können und in welcher Weise sie verschachtelt sein dürfen. Anwendungen, die das XML-Dokument interpretieren möchten, überprüfen es mit Hilfe der zugehörigen DTD/XML-Schema auf seine syntaktische Richtigkeit. Stimmt ein, so geprüftes XML-Dokument mit den Anforderugen, welche die DTD oder das XML Schema beschreiben, überein, so bezeichnet man dieses als gültig. Bekannte XML-Definitionen sind zum Beispiel MathML, mit der sich mathematische Formeln in XML beschreiben lassen, oder DocBook, mit dem sich ganze Bücher in XML verfassen lassen. Dieses Tutorial wurde übrigens ebenfalls mit DocBook erstellt.

Note

Ein XML-Dokument kann nur dann gültig sein, wenn es auch wohlgeformt ist und eine XML-Deklaration besitzt, aber nicht andersrum.

Die Überprüfungsschritte eines XML-Dokuments

An dieser Stelle sei noch kurz auf das Paradoxon hingewiesen, dass ein DTD-Dokument selbst kein XML-Dokument ist, aber durchaus sein könnte. Die daraus resultierenden Nachteile sind, dass zwei verschiedene "Sprachen" erlernt, sowie verschiedene Werkzeuge zum Interpretieren von XML- und DTD-Dokumenten verwendet werden müssen. Darüber hinaus gibt es noch viele weitere Gründe, warum es Sinn machen würde, ein XML-Dokument durch ein weiteres zu definieren. Diesen "Misstand" versucht das W3C zur Zeit zu entfernen, indem es eine XML-Sprache definiert hat, die wiederum andere XML-Dokumente definieren kann: XML Schema. Im März 2001 wurde die Version 1.0 freigegeben. Sie erlaubt eine weitaus feinere Beschränkung eines XML-Dokumentes, als DTD. XML Schema ist bereits dabei, die DTD mehr und mehr abzulösen. Mehr Informationen zum Thema XML Schema können sie auf der entsprechenden Seite des W3C finden: http://www.w3.org/XML/Schema. Zum Schmunzeln sei noch angemerkt, dass XML Schema selbst wiederum durch eine DTD begrenzt wird. Die "ultimative" DTD sozusagen. Das hat aber seinen Sinn, da ein System nicht sich selbst beschreiben kann und darf.

3. XSL - Ein XML-Dokument umwandeln

Ist ein XML-Dokument einmal korrekt definiert, so kann es entweder von der entsprechenden Anwendung interpretiert oder sein Inhalt mit Hilfe von XSLT in beliebige andere XML Dokumente "konvertiert" werden. Dafür benötigt man zum einen einen XSL-Prozessor und ein XSL-Stylesheet. Das XSL-Stylesheet sagt dem XSL-Prozessor, welche Daten (was) aus dem XML-Dokument er wie zu formatieren hat. Eine solche Konvertierung wird häufig auch als Transformation bezeichnet.

Der XSL-Prozessor

4. Von XML zu XHTML

Wenn wir HTML-Dokumente mit gängigen XML-Werkzeugen bearbeiten möchten, so müssen wir aus unserem HTML-Dokument ein gültiges XML-Dokument machen. Das Resultat heißt dann XHTML. Um genau zu sein, müsste ein echtes XHTML-Dokument noch einige Eigenschaften mehr besitzen, als die nachfolgend aufgezeigten. Wir wollen uns jedoch mit diesen begnügen, da es in erster Linie darum geht, ein HTML-Dokument so aufzubereiten, dass dieses mit gängigen XML-Werkzeugen verarbeitet werden kann. Falls Sie mehr über XHTML selbst erfahren möchten, können Sie auf den Seiten des W3C alle wichtigen Informationen darüber nachlesen: http://www.w3.org/MarkUp/. Die entscheidenden Punkte, die ein XHTML-Dokument - zusätzlich zu den Bedingungen eines XML-Dokuments - also erfüllen muss, lauten:

  • Das Wurzelelement muss eine Namensraumangabe der folgenden Form besitzen: <html xmlns="http://www.w3.org/1999/xhtml">

  • Alle Elemente und Attributnamen müssen ausnahmslos klein geschrieben werden. Falsch: <TABLE WIDTH="10">. Richtig: <table width="10">.

  • Die Doctype-Anweisung zeigt auf die entsprechend zu verwendene DTD: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> Falls Sie einen Editor verwenden, der Ihr XHTML-Dokument während der Eingabe bereits überprüft, kann dieser anhand der DTD Ihr Dokument auf die Einhaltung der XHTML-Regeln hin überprüfen. Später können dies auch andere Anwendungen, denen Ihr XHTML-Dokument vorliegt.

Im nachfolgenden Listing können Sie ein Beispiel für ein gültiges XHTML-Dokument sehen.

Example 2.1. Ein gültiges XHTML-Dokument

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title>Von HTML zu XHTML</title>
   </head>
<body>
   <p>
      Das ist eine Zeile Text. <br/>
      Das ist die nächste Zeile Text.
   </p>
</body>
</html>

Chapter 3. Java - Die unabhängige Programmiersprache

Fehler in diesem Kapitel melden. Danke!

Am 25. Mai 1995 wurde die erste Java-Version durch Sun Microsystems veröffentlicht. Java ist eine voll objektorientierte Sprache, die vollständig neu entworfen wurde. Dabei achtete man darauf, alle Vorteile von C++ zu übernehmen und die Nachteile weitestgehend außenvor zu lassen. Die grössten Unterschiede im Vergleich zu C++ sind, dass es in Java keine Pointer und keine Mehrfachvererbungen gibt. Die Entscheidung gegen diese Funktionalitäten hängt zum einen mit deren Fehlerträchtigkeit bei der Verwendung zusammen und zum anderen natürlich mit der Tatsache, dass Java plattformunabhängig ist. Deshalb sind maschinennahe Operationen nicht möglich und wurden entfernt.

Ein Java-Programm, das auf Linux programmiert wurde, kann ohne erneutes Kompilieren z.B. unter Windows oder einem anderen Betriebssystem ausgeführt werden, solange es hierfür eine sogenannte VM (Virtual Machine) gibt. Die Virtual Machine sorgt dafür, dass das Java-Programm auf das Betriebssystem "aufsetzen" kann. Es stellt also die Verbindung zwischen dem Programm eineeund dem Betriebssystem her, wobei das Programm selbst nicht verändert werden muss.

Die Rolle der Virtual Machine

Aufgrund der Plattformunabhängigkeit, sowie der grossen Anzahl erhältlicher Bibliotheken für die Netzwerkprogrammierung hat sich Java einen dauerhaften Platz in der Webentwicklung erarbeitet. So verwundert es nicht, dass Cocoon selbst in Java geschrieben wurde. Falls Sie noch nicht mit Java programmiert haben, ist dies trotzdem kein Hindernis. Die grundlegenden Funktionen, die Cocoon bereitstellt, können zum größten Teil ohne jegliche Programmierkenntnisse eingesetzt werden. Nur wenn Sie Logik verwenden oder Komponenten erweitern möchten, sollten Sie sich etwas mit der Sprache Java vertraut machen. Ein sehr gutes Buch, mit dem auch ich Java gelernt habe, ist das Handbuch der Java-Programmierung oder Java ist auch eine Insel. Mehr Literaturhinweise können Sie im Bereich Bibliography dieses Tutorials finden.

Die Sitemap ist die "Kommandozentrale" von Cocoon. Dabei handelt es sich um eine XML-Datei, in der bestimmt wird, welches XML-Dokument in welcher Reihenfolge und anhand welcher Kriterien eingelesen, transformiert und wie wieder ausgegeben werden soll. Die eigentlichen Aktionen führen die darin definierten Komponenten, wie z.B. Generatoren oder Serializer aus, die wir später noch näher betrachten werden. Im Grunde lässt sich die Sitemap in folgende Bereiche aufteilen:

  • Die Komponenten. Deren Definitionen werden innerhalb des Elements <map:components/> platziert.

  • Die Gruppierungen. Diese werden jeweils innerhalb der Elemente <map:resources/>, <map:views/>, <map:action-sets/> definiert.

  • Die Flows. Sie werden innerhalb von <map:flows/> definiert.

  • Die Pipelines. Diese werden innerhalb von <map:pipelines/> definiert.

Im nachfolgenden Listing können Sie ein Grundgerüst einer Sitemap sehen.

Example 4.1. Das Grundgerüst einer Sitemap

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <!-- Hier werden alle Komponenten registriert (Optional) -->
   </map:components>

   <map:views>
      <!-- Hier werden alle Views registriert (Optional) -->
   </map:views>

   <map:resources>
      <!-- Hier werden alle Ressourcen registriert (Optional) -->
   </map:resources>

   <map:action-sets>
      <!-- Hier werden alle Action-Sets registriert (Optional) -->
   </map:action-sets>

   <map:flows>
      <!-- Hier werden alle Flows registriert (Optional) -->
   </map:flows>

   <map:pipelines>
      <!-- Hier werden alle Pipelines definiert (Pflicht) -->
   </map:pipelines>

</map:sitemap>

Mit Ausnahme des Elements <map:pipelines/> sind alle anderen Definitionen optional.

1. Die Komponenten

Innerhalb des Elements <map:components/> werden alle "Werkzeuge" definiert, mit denen innerhalb einer Sitmap gearbeitet werden kann. In Cocoon existieren zahlreiche, sofort einsetzbare Komponten, welche die verschiedensten Aufgaben besitzen. So gibt es zum Beispiel Komponenten, die ein XML-Dokument von einem beliebigen Ort einlesen und andere, die ein XML-Dokument auf verschiedenste Arten transformieren können. Sollten Sie einmal eine - speziell an Ihre Bedürfnisse - angepasste Komponente benötigen, können Sie diese mit ein wenig Java-Kenntnissen relativ einfach selbst erstellen und dank des modularen Aufbaus einfach durch die entsprechende Definition innerhalb von <map:components/> in Cocoon einbinden und anschließend verwenden. Eine genauere Beschreibung zum "Selberbauen" von Komponenten ist auf http://cocoon.apache.org/2.1/developing/extending.html erhältlich.

Example 4.2. Der Komponenten-Bereich innerhalb der Sitema

<map:components>
   <!-- Hier werden alle Komponenten registriert -->
</map:components>

Note

Im Komponenten-Bereich müssen zuvor alle "Werkzeuge" unter einem beliebigen, eindeutigen Namen registriert werden, unter dem sie später in der Sitemap referenziert und verwendet werden können.

Figure 4.1. Die Gliederung der Komponenten

Die Gliederung der Komponenten

Wie sie in der vorhergehenden Graphik sehen können, unterteilen sich die Komponenten selbst wiederum in zwei Bereiche:

  • Logik-Komponenten: Diese Komponenten haben keinen direkten Einfluss auf die Verarbeitung von Ressourcen, dienen aber dazu, bestimmte Fallunterscheidungen innerhalb der Sitemap zu realisieren, sowie programmierte Logik zu integrieren.

  • Bearbeitungs-Komponenten: Damit sind alle Komponenten gemeint, die direkten Einfluss auf die Verarbeitung der darzustellenden Ressourcen, wie z.B. XML-Dokumente haben.

1.1. Die Logik-Komponenten

Die Logik-Komponenten ermöglichen es, innerhalb der Sitemap eine Ablaufsteuerung einzuführen. Den Komponenten werden hierfür in der Regel Werte übergeben, die sie bearbeiten oder anhand derer sie entsprechende Aktionen durchführen. Abhängig von den gegebenen Bedingungen, führen sie anschließend ihren Rumpf aus oder überspringen ihn. In den nachfolgenden Abschnitten werden wir die einzelnen Arten von Logik-Komponenten näher betrachten.

1.1.1. Die Matcher

Ein Matcher ist eine Komponente, die einen Wert entgegennimmt und gegen ein beliebigen Musters überprüft. Dieses Muster wird in den meisten Fällen mit dem Attribut pattern übergeben. Passt der Wert auf das angegebene Muster, wird der Rumpf des Elements <map:match/> ausgeführt. Es können beliebig viele Matcher definiert werden, die jedoch alle einen eindeutigen Namen besitzen müssen. Eine mehr oder weniger aktuelle Liste, welche Matcher zur Zeit für Cocoon existieren, ist auf http://cocoon.apache.org/2.1/userdocs/matchers/matchers.html zu finden.

Der mit Abstand wichtigste Matcher im Zusammenhang mit der Webentwicklung ist der WildCardURIMatcher, der den übergebenen Pattern dahingehend überprüft, ob er auf den Request-String passt. Ist dies der Fall, wird der Rumpf von <map:match/> ausgeführt. Andernfalls wird er übersprungen und das nachfolgende Element <map:match/> verarbeitet. Der WildCardURIMatcher kennt folgende Regeln für den Wert des Attributs pattern:

  • Asterisk (*) - Dieser Stern steht für 0...N beliebige Zeichen bis zum ersten Vorkommen eines Slash (/).

    Beispiel: Das Pattern *.html würde auf den Aufruf http://localhost:8080/cocoon/index.html zutreffen. Jedoch nicht auf http://localhost:8080/cocoon/irgendwas/index.html. Hierfür müsste das Pattern */*.html verwendet werden.

  • Zwei Asterisks (**) - Zwei Sterne stehen für 0...N beliebige Zeichen inklusive eines oder mehrerer Slash (/).

    Beispiel: Das Pattern ** würde alle Aufrufe für gültig erklären. Hingegen **/index.html nur solche Aufrufe für gültig erklären würde, die in der Mitte eine beliebige Angabe besitzen, am Schluss jedoch immer mit /index.html enden. Gültig wäre demnach http://localhost:8080/foo/bar/index.html. Ungültig wäre http://localhost:8080/foo/bar/mysite.html.

  • Der Backslash (\) - Er wird verwendet, um Fluchtsequenzen erzeugen zu können. D.h., dass auch der Stern und der Backslash selbst in der URI verwendet werden können.

    Beispiel: Das Pattern \* würde den Aufruf http://localhost:8080/cocoon/* für gültig erklären. Bitte beachten Sie, dass hier der Stern nun nicht als "Platzhalter" für beliebig viele Zeichen steht, sondern selbst als Zeichen interpretiert wird! Ein Aufruf von http://localhost:8080/cocoon/index.html würde hier also als ungültig zurückgewiesen werden. Genauso kann der Backslash auch dazu verwendet werden, sich selbst zu markieren. Ein Pattern \\ würde den Aufruf http://localhost:8080/cocoon/\ für gültig erklären.

Note

Die Pipeline, in der das Element <map:match/> definiert wird, wird von oben nach unten abgearbeitet. D.h., dass der Rumpf des ersten passenden Match-Elementes ausgeführt wird. Nach der Ausführung des Rumpfes von <map:match/> wird die Abarbeitung der Sitemap beendet.

Example 4.3. Beispiel der Verwendung eines Matchers

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <map:matchers default="wildcard">
         <!-- Hier wird der Matcher eingebunden -->
         <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher"/>
      </map:matchers>
   </map:components>

   <map:pipelines>
      <map:pipeline>
         <!-- Hier wird der Matcher verwendet -->
         <map:match type="wildcard" pattern="index.html">
            <!-- Rumpf mit Anweisungen -->
         </map:match >
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

In diesem Beispiel wird innerhalb einer Sitemap ein Matcher definiert, der seinen Rumpf nur dann ausführt, wenn der Request aus folgendem Aufbau besteht: http://localhost:8080/cocoon/index.html. Alle Anfragen, die auf dieses Muster passen, bewirken, dass der Rumpf von <map:match type="wildcard" pattern="index.html"> ausgeführt wird. Innerhalb dieses Rumpfes könnten nun weitere Anweisungen stehen, wie zum Beispiel das Lesen eines XML-Dokumentes sowie eines XSL-Dokumentes und das anschließende Umwandeln in ein XHTML-Dokument. Bitte beachten Sie, dass mit dem Attribut type der Matcher aus der Komponentendefinition innerhalb des Elements <map:matchers/> explizit bestimmt wird. In vielen Fällen wird dieses Attribut jedoch weggelassen. In diesem Fall wird automatisch derjenige Matcher, welcher durch das Attribut default deklariert ist, verwendet.

1.1.2. Die Selectoren

Ein Selector ist im Grunde ein Matcher mit dem einen Unterschied, dass er innerhalb seines Rumpfes zusätzlich die Verzweigungsäste durch Verwendung der Elemente <map:when/> sowie <map:otherwise/> definieren kann. Er ermöglicht also eine gewisse "Switch"-Logik. Eine Übericht über zur Zeit verfügbare Selectoren erhalten Sie auf folgender Website: http://cocoon.apache.org/2.1/userdocs/selectors/selectors.html.

Example 4.4. Beispiel zur Verwendung eines Selectors

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <map:matchers default="wildcard">
         <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher" />
      </map:matchers>
      <map:selectors>         
         <!-- Hier wird der Selector eingebunden und konfiguriert -->
         <map:selector name="browser" src="org.apache.cocoon.selection.BrowserSelector">
            <browser name="explorer" useragent="MSIE"/>
            <browser name="netscape" useragent="Mozilla"/>
         </map:selector>
      </map:selectors>
   </map:components>

   <map:pipelines>
      <map:pipeline>
         <map:match pattern="*">            
            <!-- Hier wird der Selector verwendet -->
            <map:select type="browser">
               <map:when test="netscape">
                  <!-- Rumpf mit Anweisungen für Netscape -->
               </map:when>
               <map:otherwise>
                  <!-- Rumpf mit Anweisungen für alle anderen Browser-->
               </map:otherwise>
            </map:select>
         </map:match>
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

Hier wird also innerhalb der Sitemap ein Selector definiert, der die Aufgabe hat, zu überprüfen, welchen Browser der Client verwendet. Der Selector selbst liest in diesem Beispiel den Header des Request aus und vergleicht den Inhalt mit dem, als Attribut test übergebenen Wert. Stimmen diese beiden Angaben überein, so wird der Rumpf von <map:when/> ausgeführt. Für alle nicht genannten Browser wird hingegender Rumpf von <map:otherwise> ausgeführt. DasElement <map:when/> kann beliebig oft innerhalb von <map:select/> verwendet werden. Das Element <map:otherwise/> hingegen nur genau einmal. Der Inhalt von <map:select/> wird sequentiell von oben nach unten abgearbeitet.

Note

Ein Selector ist eine Komponente, die innerhalb ihres Rumpfes eine Art "Switch"-Logik erlaubt. Der Rumpf des Elementes <map:when/> innerhalb von <map:select/> wird nur dann ausgeführt, wenn der Selector <map:selector/> eine wahre Aussage (true) zurückliefert. Andernfalls wird der Rumpf von <map:otherwise/> ausgeführt. Dieses Element darf nur ein einziges mal innerhalb von <map:select/> vorkommen.

1.1.3. Die Actions

Zu denjenigen Logik-Komponenten, die am häufigsten an die eigenen Bedürfnisse angepasst werden oder sogar komplett neu geschrieben werden, gehören die Actions. Actions sind - genau wie alle anderen Komponenten - Java-Klassen die bestimmten Richtlinien folgen. Innerhalb eine Action-Klasse kann eine beliebig aufwändige Logik platziert werden, die genau dann ausgeführt werden soll, wenn der entsprechende Punkt innerhalb der Pipeline erreicht wurde, an dem die zugehörige Action platziert wurde. Eine häufig verwendete Aufgabe für eine Action könnte zum Beispiel darin bestehen, eine Verbindung zu einer Datenbank herzustellen, bestimmte Werte auszulesen und anschließend der Pipeline für die weitere Verarbeitung zur Verfügung zu stellen. Innerhalb von Actions ist ein Zugriff z.B. auf Request- oder Session-Attribute möglich.

Neben der Implementierung beliebig komplexer, eigener Logik besteht mit einer Action zusätzlich noch die Möglichkeit,, ebenfalls eine Fallunterscheidung innerhalb der Sitemap zu realisieren, die sich in der Ausführung des Rumpfes von <map:act/> oder dem Überspringen ausdrückt. Ob der Rumpf von <map:act/> ausgeführt wird, hängt davon ab, ob die Action den Wert null oder eine Java-Map, die auch leer sein darf, zurück liefert. Im ersteren Fall wird der Rumpf von <map:act/> nicht ausgeführt. Falls die zurückgelieferte Java-Map Name-Wert-Paare enthält, so kann auf diese innerhalb des Rumpfes von <map:act/> direkt mit dem entsprechenden Schlüssel zugegriffen werden. Der Gültigkeitsbereich der zurückgelieferten Map beschränkt sich ausschließlich auf den Rumpf der Action. Außerhalb dieses Rumpfes haben die Name-Wert-Paare keine Gültigkeit. D.h., es kann nicht darauf zugegriffen werden. Umgekehrt ist es jedoch durchaus möglich, auf einen Parameter einer äußeren Action zuzugreifen, falls mehrere Actions inneinander verschachtelt sind, was durchaus möglich ist.

Example 4.5. Beispiel zur Verwendung einer Action

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <map:matchers default="wildcard">
         <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher"/>
      </map:matchers>
      <map:actions>
         <!-- Hier wird die Action definiert -->
         <map:action name="myAction" src="foo.bar.MyAction"/>
      </map:actions>
   </map:components>

   <map:pipelines>
      <map:pipeline>
         <map:match type="bild.jpg">
            <!-- Hier wird die Action verwendet -->
            <map:act type="myAction">
               <!-- Wird nur ausgeführt, wenn eine Java-Map zurück geliefert wird -->
            </map:act>
            ...
         </map:match>
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

Um auf einen Action-Parameter innerhalb des Rumpfes von <map.act/> zuzugreifen, ist der Name des Parameters in geschweifte Klammern zu setzen. Beispiel: {foo}

Example 4.6. Beispiel zur Verwendung eines Action-Parameters

<map:act type="myAction">
   <map:read src="{filename}"/>
</map:act>

1.2. Die Bearbeitungs-Komponenten

Diese Komponenten führen eine Bearbeitung von XML-Dokumenten, SAX-Events und anderen Resourcen durch. Stichpunktartig könnte man die Aufgaben dieser Komponenten folgendermaßen aufzählen: Lesen, Interpretieren und Ausgeben von XML-Dokumenten, sowie anderen Resourcen, wie z.B. Bilddateien. Bei XML-Dokumenten kommt zusätzlich noch der Punkt "Umwandeln" von einem XML-Dokument in ein anderes oder in ein bestimmtes Format hinzu. Bei diesem Punkt ist es zunächst wichtig, zu wisssen, auf welche Weise Cocoon ein XML-Dokument verarbeitet.

1.2.1. Der SAX-Stream

Bevor Cocoon ein XML-Dokument bearbeiten, also z.B. in ein anderes XML-Dokument transformieren kann, muss es zu nächst einen sogenannten SAX-Stream (=SAX-Events) erzeugen. D.h., es muss aus einer gegebenen Ressource, wie z.B. einer lokalen XML-Datei oder der Struktur eines Dateisystems einen XML-Strom erzeugen, der anschließend durch alle angegebenen Bearbeitungs-Komponenten durchgeschleust wird. Wenn ein solcher SAX-Stream an einer Bearbeitungs-Komponentene angekommen ist, führt diese Komponente bestimmte Aktionen aus und/oder verändert den SAX-Stream selbst. Anschließend wird der Stream an die nächste Komponente weiter gegeben. Falls es sich um die letzte Komponente innerhalb einer Pipeline handelt, wird der SAX-Stream anschließend in das Zielformat gewandelt und an den Client ausgegeben. Welche verschiedenen Bearbeitungs-Komponenten es gibt, um einen solchen SAX-Stream zu verarbeiten, erfahren Sie in den folgenden Abschnitten.

Figure 4.2. Der SAX-Stream dient als Schnittstelle für alle Bearbeitungs-Komponenten

Der SAX-Stream dient als Schnittstelle für alle Bearbeitungs-Komponenten

Note

Strukturierte Daten, die später verarbeitet werden sollen, müssen immer zuerst in einen SAX-Stream umgewandelt werden, damit andere Komponenten die XML-Daten lesen und darauf reagieren können. Ein SAX-Stream dient also in gewisser Weise als Abstraktionsschicht für die übrigen Komponenten, welche die XML-Strukturen verwenden.

1.2.2. Die Generatoren

Die Generatoren sind dafür gedacht, beliebige strukturierte Daten in einen SAX-Stream zu wandeln. Dies können XML-Dokumente von der Festplatte, über HTTP oder aus einer Datenbank sein. Es kann sich hierbei aber auch um einen Generator handeln, der "nicht-XML-Daten" in einen SAX-Stream und somit XML-Daten umwandelt (z.B. Struktur des Dateisystems). Nachdem der Generator einen SAX-Stream erzeugt hat, reicht er diese an die nachfolgende Komponente, etwa einen Transformator oder einen Serializer weiter. Ein Generator ist in der Regel immer die erste Angabe in einer Pipeline. Welche verschiedenen Generator-Komponenten Cocoon bereits zur Verfügung stellt, können Sie hier nachschlagen: http://cocoon.apache.org/2.1/userdocs/generators/generators.html.

Example 4.7. Beispiel zur Verwendung eines Generators

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <map:matchers default="wildcard">
         <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher"/>
      </map:matchers>
      <map:generators>
         <!-- Hier wird der Generator eingebunden -->
         <map:generator name="file" src="org.apache.cocoon.generation.FileGenerator"/>
      </map:generators>
   </map:components>

   <map:pipelines>
      <map:pipeline>
         <map:match type="index.html">
            <!-- Hier wird der Generator verwendet -->
            <map:generate type="file" src="document.xml"/>
            ...
         </map:match>
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

In diesem Beispiel wird die Verwendung eines Generators innerhalb einer Sitemap gezeigt. Dabei wird der Generator bereits mit einem Matcher kombiniert, was auch die Regel ist. Erfolgt ein Aufruf der Form http://localhost:8080/cocoon/index.html, so wird der Rumpf des Matchers ausgeführt und somit durch den File-Generator eine Datei mit dem Namen document.xml vom Dateisystem gelesen und in einen SAX-Stream umgewandelt, welcher wiederum von der nachfolgenden Komponenten innerhalb der Pipeline weiterverarbeitet werden kann. Hinweis: Dieses Beispiel ist so nicht lauffähig! Es fehlt eine nachfolgende Komponente, wie z.B. der Serializier der später erläutert wird.

1.2.3. Die Transformatoren

Wenn einmal ein XML-Dokument in einen SAX-Stream umgewandelt vorliegt, kommen die Transformatoren ins Spiel. Aufgabe dieser optionalen Bearbeitungs-Komponente ist es, diesen SAX-Stream in einen beliebigen anderen SAX-Stream umzuwandeln. Gesteuert wird dies oft durch eine externe Datei (z.B. XSLT-Stylesheet), die eingelesen wird. Auch eine Menge verschiedener Transformers werden durch Cocoon bereits zur Verfügung gestellt. Welche dies sind, können Sie hier nachschlagen: http://cocoon.apache.org/2.1/userdocs/transformers/transformers.html.

Example 4.8. Beispiel zur Verwendung eines Transformators

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <map:matchers default="wildcard">
         <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher"/>
      </map:matchers>
      <map:generators>
         <map:generator name="file" src="org.apache.cocoon.generation.FileGenerator"/>
      </map:generators>
      <map:transformers>
         <!-- Hier wird der Transformator eingebunden -->
         <map:transformator name="xsl" src="org.apache.cocoon.transformation.TraxTransformer"/>
      </map:transformers>
   </map:components>

   <map:pipelines>
      <map:pipeline>
         <map:match type="index.html" >
            <map:generate type="file" src="document.xml"/>
            <!-- Hier wird der Transformator verwendet -->
            <map:transform type="xsl" src="document2html.xsl"/>
            ...
         </map:match>
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

Dieses Beispiel verwendet nun schon drei verschiedene Komponenten: einen Matcher, einen Generator und einen Transformator. Auch hier werden alle Komponenten als erstes innerhalb von <map:components/> registriert, bevor sie verwendet werden können. In der Pipeline wird wieder festgelegt, dass alle Aufrufe der Form http://localhost:8080/cocoon/index.html entgegengenommen und die im Rumpf definierten Komponenten ausgeführt werden sollen. Somit wird also durch den Generator das Dokument document.xml von der Festplatte gelesen und in SAX-Events umgewandelt. Dieser SAX-Stream wird daraufhin vom Transformator entgegengenommen und in einen anderen SAX-Stream umgewandelt. Die Art der Umwandlung wird hier zum einen durch den Transformator selbst und zum anderen durch das angegebene XSLT-Stylesheet document2html.xsl angegeben. Bitte beachten Sie, dass auch dieses Beispiel so nicht lauffähig ist, da eine Sitemap über mindestens einen Generator und genau einen Serializer verfügen muss.

1.2.4. Die Serializer

Mit den bis hierher vorgestellten Komponenten könnten wir nun bereits SAX-Streams anhand beliebiger Strukturen und von beliebigen Orten lesen und weiterverarbeiten. Leider würde uns das nicht viel nützen, da wir das Ergebnis nicht betrachten könnten. Hierfür benötigen wir noch den dritten Teil der Bearbeitungs-Komponenten: Die Serializer.

Ein Serializer ist im Allgemeinen diejenige Komponente, welche den SAX-Stream in ein beliebiges binäres oder textuelles Format, wie z.B. ein HTML- oder ein PDF-Dokument umwandelt. Er steht immer am Ende einer Pipeline. Nach dem der Serializer eine solche Umwandlung durchgeführt hat, wird das Ergebnisdokument in der Regel an den Client versendet. Die verschiedenen Serializer werden hier vorgestellt: http://cocoon.apache.org/2.1/userdocs/serializers/serializers.html.

Example 4.9. Beispiel zur Verwendung eines Serializers

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <map:matchers default="wildcard">
         <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher"/>
      </map:matchers>
      <map:generators>
         <map:generator name="file" src="org.apache.cocoon.generation.FileGenerator"/>
      </map:generators>
      <map:transformers>
         <map:transformator name="xsl" src="org.apache.cocoon.transformation.TraxTransformer"/>
      </map:transformers>
      <map:serializers>
         <!-- Hier wird der Serializer eingebunden -->
         <map:serializer name="html" mime-type="text/html" src="org.apache.cocoon.serialization.HTMLSerializer"/>
      </map:serializers>
   </map:components>

   <map:pipelines>
      <map:pipeline>
         <map:match type="index.html" >
            <map:generate type="file" src="document.xml" />
            <map:transform type="xsl" src="document2html.xsl"/>            
            <!-- Hier wird der Serializer verwendet -->
            <map:serialize type="html" />
         </map:match>
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

Dieses Beispiel verwendet nun schon vier verschiedene Komponenten: einen Matcher, einen Generator, einen Transformator und einen Serializer. Auch hier werden alle Komponenten als erstes innerhalb von <map:components/> registriert, bevor sie verwendet werden können. In der Pipeline wird wieder festgelegt, dass alle Aufrufe der Form http://localhost:8080/cocoon/index.html entgegen genommen und die im Rumpf definierten Komponenten ausgeführt werden. Somit wird also durch den Generator das Dokument document.xml von der Festplatte gelesen und in SAX-Events umgewandelt. Dieser SAX-Stream wird daraufhin vom Transformator entgegen genommen und in einen anderen SAX-Stream umgewandelt. Die Art der Umwandlung wird hier zum einen durch den Transformator und dessen Definition selbst und zum anderen durch das angegebene XSL-Dokument angegeben. Anschließend erfolgt die Ausgabe des SAX-Streams als HTML durch den HTML-Serializer. Bitte beachten Sie bei diesem Beispiel, dass der Mime-Type bei der Registrierung explizit angegeben werden muss!

1.2.5. Die Reader

Readers werden verwendet, um das Lesen und Ausgeben von Daten in einem Zug zu ermöglichen. Sie sind sozusagen eine Kombination von Generatoren und Serializern ohne den Umweg über die Transformator-Komponenten. Dies ist nützlich für Dateien, die so weitergegeben werden sollen, wie sie eingelesen wurden (z.B. Bilder oder Texte) und nicht den Umwandlungsprozess innerhalb einer Pipeline durchlaufen, also in einen SAX-Stream verwandelt werden müssen. Reader beenden die Abbarbeitung der Sitemap nach ihrer Ausführung. Welche Reader zur Zeit in Cocoon existieren, können Sie auf folgender Website nachlesen: http://cocoon.apache.org/2.1/userdocs/readers/readers.html.

Example 4.10. Beispiel zur Verwendung eines Readers

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <map:matchers default="wildcard">
         <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher" />
      </map:matchers>
      <map:readers>
         <!-- Hier wird der Reader eingebunden -->
         <map:reader name="resource" src="org.apache.cocoon.reading.ResourceReader"/>
      </map:readers>
   </map:components>

   <map:pipelines>
      <map:pipeline>
         <map:match type="bild.jpg" >
            <!-- Hier wird der Reader verwendet -->
            <map:read type="resource" src="resources/irgendeinbild.jpg" mime-type="image/jpg"/>
         </map:match>
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

Im obrigen, einfachen Beispiel werden ein Matcher und ein Reader registriert. Jeder Aufruf der Form http://localhost:8080/cocoon/bild.jpg hat zur Folge, dass das Bild irgendeinbild.jpg gelesen und direkt an den Client als JPG verschickt wird, ohne durch irgendwelche weiteren Prozesse laufen zu müssen. Durch das optionale Attribut mime-type kann der MimeTyper der Ressource explizit angegeben werden. Dies ist in der Regel jedoch nicht notwendig, da dieser durch den Reader selbst automatisch ermittelt wird.

2. Die Gruppierungen

Diese Elemente der Sitemap können dazu verwendet werden, bestimmte Arten von Komponenten zusammenzufassen, um diese in verschiedenen Bereichen innerhalb der Pipeline wiederverwenden zu können. Dadurch lassen sich zum Beispiel Fehler vermeiden, sowie die Übersicht steigern. Zur Zeit gibt es drei verschiedene Bereiche, innerhalb derer die verschiedenen Gruppierungen definiert werden:

  • <map:resources/>

  • <map:views/>

  • <map:action-sets/>

Note

Gruppierungen fassen eine bestimmte Art von Komponenten unter einem bestimmten Namen zusammen, um sie mehrfach verwendbar zu machen.

Figure 4.3. Die Gliederung der Gruppierungen

Die Gliederung der Gruppierungen

2.1. Die Resourcen

Resourcen sind "wiederverwendbare Pipelines". D.h., dass innerhalb einer Resource alle Komponenten verwendet werden können, die auch in einer Pipeline Verwendung finden würden. Darunter zählen z.B. Generatoren, Transformatoren, Serializer, Reader, Actions, usw. Die entsprechende Resource kann anschließend über ihren eindeutigen Namen angesprochen und ausgeführt werden. Der Aufruf einer Resource erfolgt unter Verwendung des Elements <map:call resource="[name]"/>. Wobei hier [name] für den eindeutigen Namen der Resource steht.

Example 4.11. Beispiel der Verwendung einer Resource

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

  <!-- Hier werden alle benoetigten Komponenten registriert -->
   <map:components>
      <map:matchers default="wildcard">
         <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher" />
      </map:matchers>
      <map:generators>
         <map:generator name="file" src="org.apache.cocoon.generation.FileGenerator" />
      </map:generators>
      <map:transformers>
         <map:transformator name="xslt" src="org.apache.cocoon.transformation.TraxTransformer"/>
      </map:transformers>
      <map:serializers>
         <map:serializer name="html" mime-type="text/html" src="org.apache.cocoon.serialization.HTMLSerializer"/>
      </map:serializers>
   </map:components>

   <map:resources>
      <-- Hier wird die Resource definiert -->
      <map:resource name="convert" >
         <map:generate type="file" src="dokument.xml" /<
         <map:transform type="xslt" src="doc2html.xsl" />
      </map:resource>
   </map:resources>

   <map:pipelines>
      <map:pipeline>
         <map:match type="index.html" >
            <!-- Hier wird auf die Resource verwiesen -->
            <map:call resource="convert"/>
            <map:serialize type="html"/>
         </map:match>
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

In diesem Beispiel wird die Funktionialität der Pipeline mit Ausnahme der Serialisierung vollständig in die Resource mit dem Namen convert verlagert. Unter Verwendung dieses Namens könnten nun auch beliebige andere Sitemaps diese Resource aufrufen.

Note

Bis zur Version 2.1 von Cocoon wurde aus einer aufgerufenen Resource nicht zurück gekehrt. Aus diesem Grunde musste eine Resource entweder eine komplette Pipeline darstellen oder am Ende eine weitere Resource aufrufen, die mit einem Serializer endet. Alle aktuellen Versionen hingegen erlauben eine vollständige, beliebige Aufteilung einer Pipeline in verschiedene Resourcen und kehren nach ihrer Abarbeitung an den aufrufenden Ort zurück..

2.2. Die Views

[Abschnitt folgt in Kürze]

2.3. Die Action-Sets

[Abschnitt folgt in Kürze]

3. Die Pipelines

[Abschnitt folgt in Kürze]

[ Folgt in Kürze]

Chapter 6. XSP - Extensible Server Page

Fehler in diesem Kapitel melden. Danke!

XSP (Extensible Server Pages) wurde von der Cocoon-Gemeinde entwickelt und ist integrierter Bestandteil von Cocoon. Eine Extensible Server Page ist ein XML-Dokument, in dem Logik eingebettet wurde, die speziell markiert ist. Dies ist in etwa vergleichbar mit JSP (JavaServerPages) oder PHP. Dort wird in ein HTML Dokument ein, durch spezielle Tags markierter Code eingefügt, der später durch einen Interpreter serverseitig ausgeführt und wieder entfernt wird. Anders wäre dies in einer Programmiersprache der Fall, die HTML-Code erzeugt. Hier müssten die Tags durch die entsprechenden Output-Anweisungen ausgegeben werden und somit das gesamte HTML-Dokument durch die Output-Anweisungen aufgebaut werden.

Note

Bitte beachten Sie, dass XSP lange Zeit in Cocoon das bevorzugte Mittel war, um Logik in eine Cocoon-Applikation zu integrieren. Seit Cocoon-Version 2.1 nimmt diese Position mehr und mehr die Control-Flow-Technik ein. XSP wird in den nächsten Releases voraussichtlich sogar aus dem Core entfernt und steht ab da an nur mehr als optionaler Block zur Verfügung. Aufgrund dieser Tatsache sollten Sie zuvor gründlich überlegen, welche Technik sie einsetzen möchten, da Control-Flow gegenüber XSP einige wesentliche Vorteile mit sich bringt.

Figure 6.1. Die verschiedenen Arten, Logik einzubinden

Die verschiedenen Arten, Logik einzubinden

Das XSP-Dokument wird durch einen XSP-Parser (ServerPagesGenerator) interpretiert, der die Logik-Bestandteile der XSP-Datei in Java-Code umwandelt und anschließend ausführt. Sehen wir uns hierzu eine einfache XSP-Datei an:

Example 6.1. Eine einfache XSP-Datei

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

<xsp:page language="java" xmlns:xsp="http://apache.org/xsp">

<xsp:logic>
   private int value = 0;

   private int add() {

      return (value = value + 1);
   }
</xsp:logic>

<page>
   <title>Seitenzähler</title>
   <content>
      Diese Seite wurde <xsp:expr>add()</xsp:expr> mal aufgerufen.
   </content>
</page>
</xsp:page>

Zu Beginn definieren wir ein Element <xsp:page/>, dem wir den Namensraum http://apache.org/xsp zuweisen, sowie das Attribut language, das die , zu verwendende Programmiersprache auf java setzt. Dieses einfache XSP-Dokument weißt nun einer Variablen value den Wert 0 zu. Durch Aufruf der Methode add() wird immer 1 hinzuaddiert. Zum Schluss wird das Ergebnis der Addition mit <xsp:expr/> ausgegeben.

Note

Innerhalb des Elements <xsp:logic/> können Sie beliebigen Java-Code platzieren. Aber Achtung, alles was Sie innerhalb von <xsp:logic/> platzieren muss denselben Regeln folgen, als wenn Sie diesen Inhalt innerhalb des Rumpfes einer Java-Klasse definieren würden. Sie können hier z.B. keine Berechnungen über primitive Datentypen (int, char, ...) ausführen. Dafür müssen Sie - wie unter Java üblich - eine Methode definieren, in der diese Berechnungen vorgenommen werden, wie im Listing gezeigt wird.

Example 6.2. Platzierung in einer Java-Klasse

...
public class ExampleClass {
   
   // Alles was Sie zwischen <xsp:logic> und </xsp:logic> hinzufügen, würde
   // theoretisch hier platziert werden und muss somit den gleichen Regeln
   // folgen, die auch hier gelten.

}
...

Damit diese Logik auch interpretiert wird, müssen wir die gesamte XSP-Datei durch einen XSP-Parser = ServerPagesGenerator schicken, der die Programmierlogik aus der Datei entfernt und eine Java-Klasse daraus generiert. Das XML-Dokument ohne XSP-Logik würde anschließend so aussehen:

Example 6.3. XSP-Datei nach dem Interpretieren

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

<page>
   <title>Seitenzähler</title>
   <content>
      Diese Seite wurde 1 mal aufgerufen.
   </content>
</page>

Es handelt sich hierbei also um ein ganz normales XML-Dokument, das wir beliebig durch Transformatoren oder Serializer zum Beispiel weiterverarbeiten können. Falls Sie die generierte Java-Klasse ansehen möchten, müssen Sie - nachdem Sie Ihre XSP-Datei einmalig ausgeführt haben - im Verzeichnis "tmp/cocoon-files/org/apache/cocoon/www" unter dem Namen der XSP-Datei nachsehen. Hier sollte sich eine *.java Datei befinden, bei der alle Punkte im Namen Ihrer XSP-Datei durch Unterstriche _ ersetzt wurden. Wenn Sie diese Datei mit einem Texteditor öffnen, können Sie den Java-Code - der für Ihre XSP-Datei automatisch erstellt wurde - ansehen.

Figure 6.2. Der ServerPagesGenerator

Der ServerPagesGenerator

Welcher Generator auf das XSP-Dokument "angewendet" werden soll, müssen Sie in der Datei sitemap.xmap angeben. Angenommen, Sie haben die oben genannte XSP-Datei im Verzeichnis xml/samples unter dem Namen xsptest.xsp im Cocoon-Verzeichnis abgelegt, so könnte der Eintrag in der sitemap.xmap folgendermassen lauten:

Example 6.4. Verarbeitung einer XSP-Datei registrieren

<map:generators>
   <map:generator name="serverpages" src="org.apache.cocoon.generation.ServerPagesGenerator"/>
</map:generators>
...
<map:pipeline>

   <map:match pattern="xsptest">
      <map:generate type="serverpages" src="xml/samples/xsptest.xsp" />
      <map:serialize type="xml" />
   </map:match>

</map:pipeline>
...

Nach einem Aufurf der URL htp://localhost:8080/cocoon/xsptest sollten Sie das interpretierte XSP-Dokument angezeigt bekommen.

Note

Die, in der Client-Server Entwicklung, erfahrenen Leser werden sich sicherlich wundern, weshalb nach einem Reload der Counter nicht bei 1 beginnt, obwohl wir die Variable value nicht static gemacht haben und auch sonst keine Vorkehrungen getroffen haben, den aktuellen Zustand zu erhalten. Das liegt daran, dass Cocoon beim ersten Aufruf das entsprechende Objekt erstellt und ausführt. Es wird ab da ständig im Speicher gehalten, um einen schnelleren Zugriff zu ermöglichen. Mit jedem Reload wird also auf das selbe, im Speicher befindliche Objekt zugegriffen und dessen value erhöht.

Ein XSP-Dokument ist nicht an eine bestimmte Sprache gebunden. In den meisten Fällen wird hierfür jedoch Java verwendet. Welche Sprache letztendlich verwendet werden soll, hängt davon ab, welche im Dokument selbst deklariert wurde. Wir werden in unseren Beispielen ausschließlich Java als XSP-Programmiersprache verwenden. Falls Sie sich darüber informieren möchten, wie Sie auch andere Sprachen in XSP verwenden können, möchte ich Sie an dieser Stelle auf die Cocoon-Websites verweisen: http://cocoon.apache.org/2.1/userdocs/xsp/index.html.

Zusammenfassend kann also festgehalten werden, dass ein vollständiges XSP-Dokument den Namensraum http://apache.org/xsp eingebunden, die Programmiersprache definiert und alle Logik-Anweisungen in den entsprechenden Elementen eingbettet haben muss. Welche XSP-Elemente es gibt, können Sie auf den Wiki-Pages nachschlagen: http://wiki.apache.org/cocoon/XSPSyntax.

Chapter 7. Tutorial 1 - "Hello world!"

Fehler in diesem Kapitel melden. Danke!

In diesem Tutorial wollen wir den obligatorischen Text "Hello World!" per Cocoon ausgeben. Natürlich könnten wir den Text in die beliebigsten Dateiformate konvertieren. Wir wählen zu Beginn aber die einfachste Variante: Den Text im Format HTML oder genauer gesagt, als XHTML auszugeben. Für dieses Vorhaben sind drei einfache Schritte notwendig:

  • Definieren einer XML-Datei die den Inhalt der Seite definiert = Content

  • Erstellen eines XSLT-Stylesheets, welches das Aussehen der XHTML-Seite definiert = Layout

  • Registrieren der Komponenten in der Sitemap

Wenn man sich diesen Ablauf ansieht, kann man schon erahnen, welchen Vorteil Cocoon gegenüber vielen, zur Zeit gebräuchlichen Arten der Formatkonvertierung hat: Soll der Inhalt in einem anderen Format ausgegeben werden, so müssen lediglich die letzten zwei Schritte angepasst werden. Es muss ein Stylesheet erstellt werden, das den Inhalt entsprechend dem Zieldokument und den eigenen Vorstellungen beschreibt und zum anderen muss in der Sitemap das neue Stylesheet registriert werden.

1. Erstellen einer Sub-Applikation

Bevor Sie mit diesem Tutorial fortfahren, erstellen Sie bitte innerhalb des Verzeichnisses cocoon ein Unterverzeichnis mit dem Namen helloworld. In dieses Unterverzeichnis werden anschließend alle erstellten Skripte und Dokumente abgelegt. Dies hat den entscheidenden Vorteil, dass Sie die Dateien im Wurzelverzeichnis - wie z.B. die Main-Sitemap - nicht verändern müssen und bei Bedarf die Tutorials schnell wieder entfernen können, indem Sie einfach das entsprechende Verzeichnis löschen. Alle Sub-Applikationen erhalten später ihre eigene Sub-Sitemap. Diese wird automatisch von der übergeordneten Main-Sitemap "gemountet", d.h. in diesem Falls, dass alle Aufrufe der Form http://localhost:8080/cocoon/helloworld/** automatisch an die Sub-Sitemap weitergegeben werden.

2. Erstellen der XML-Datei

Wir einigen uns darauf, alle unsere XML-Dateien im Verzeichnis helloworld/samples abzulegen. Natürlich könnte dieser Ort beliebig gewählt werden, da er in der sitemap.xmap definiert wird. Erstellen Sie im angegebenen Verzeichnis eine Datei mit dem Namen helloworld.xml, öffnen Sie diese anschließend mit Ihrem XML-Editor und fügen Sie folgenden Eintrag hinzu:

Example 7.1. helloworld.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<page>
   <title>Tutorial 1</title>
   <content>
      <header>Hello World!</header>
      <text>Dies ist ein beliebiger Text</text>
   </content>
</page>

Diese wohlgeforme XML-Datei beschreibt also den Inhalt der Website, die später automatisiert erstellt werden soll. Bitte achten Sie unbedingt auf Encoding ISO-8859-1. Dieser ist insofern wichtig, als dass wir Umlaute und verschiedene Sonderzeichen in unserem "Content" verwenden möchten.

3. Erstellen des XSLT-Stylesheets

Nachdem wir nun den Inhalt unserer Seite in der Datei helloworld.xml definiert haben, machen wir uns daran, diesen Inhalt so zu gestalten, dass wir ihn mit einem Web-Browser im Format XHTML betrachten können. Dadurch müssen wir den Inhalt der definierten Elemente, wie beispielsweise <header/> oder <text/> an entsprechende Positionen im XHTML-Dokument setzen.

Auch für alle unsere Stylesheets legen wir einen gemeinsamen Ort fest: Das Verzeichnis helloworld/stylesheets. Und auch hier soll gesagt sein, dass dieser Ort natürlich beliebig in der Datei sitemap.xmap verändert werden kann. Wie und wo man das in dieser Datei einstellt, wird später in diesem Tutorial gezeigt.

Da das XSLT-Stylesheet auch ein XML-Dokument ist, gelten natürlich auch hierfür alle Regeln, wie für ein XML-Dokument. Mit einer wichtigen Ausnahme: Alle Werte, die in einem XSL-Dokument gefunden werden und nicht zur XSL-Spezifikation gehören, werden nicht als Fehler deklariert, sondern gelangen unverändert in die Ausgabe. Dies hat den entscheidenden Vorteil, dass man z.B. beliebige HTML-Tags verwenden kann, ohne diese speziell markieren zu müssen, was in einem "normalen" XML-Dokument der Fall wäre. Hier müsste man mit sogenannten Fluchtsequenzen arbeiten. Also zum Beispiel &gt; für >. Erstellen Sie nun im Verzeichnis stylesheets eine Datei mit dem Namen helloworld2html.xsl und platzieren Sie darin das Grundgerüst des zukünftigen Zieldokuments:

Example 7.2. helloworld2html.xsl

<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title></title>
</head>
<body></body>
</html>

Nun müssen an unserem XHTML-Dokument noch einige Anpassungen vorgenommen werden, um es zu einem Stylesheet zu machen. Das einzige Wurzelelement muss entweder <xsl:stylesheet/> oder <xsl:transform/> lauten und nicht <html/> wie das bis jetzt der Fall ist. Die Elemente <stylesheet/> und <transform/> stehen im Übrigen als Synonym zueinander. Welches von beiden Sie verwenden, bleibt also Ihnen überlassen. Am häufigsten findet man aber <stylesheet/> in den Dokumenten vor. Innerhalb dieses Tags müssen noch das Attribute version und der der Namensraum an das Präfix xsl gebunden werden. Für jedes XSLT-Stylesheet lautet der Namensraum: http://www.w3.org/1999/XSL/Transform. Ändern Sie das Dokument helloworld2html.xsl anschließend entsprechend ab:

Example 7.3. helloworld2html.xsl mit Stylesheet-Wurzelelement

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title></title>
</head>
<body></body>
</html>
</xsl:stylesheet>

Unser Dokument sieht doch schon ganz brauchbar aus. Ist es aber leider immer noch nicht. Ein weiterer wichtiger Punkt ist zu beachten: Jede Transformation beginnt an einem bestimmten Element des XML-Dokumentes. Dieses Element wird mit <xsl:template match="[Element"]> bestimmt. Damit wird der Anwendung mitgteilt, ab welcher Wurzel zu suchen begonnen werden soll. Natürlich ist diese Anweisung noch für wesentlich mehr Anwendungsfälle wichtig. Diese sollen aber an dieser Stelle nicht weiter interessieren. Ein XSL-Dokument muss mindestens ein solches Element besitzen! In unserem Beispiel ist die Wurzel, ab dem die Verarbeitung des XML-Dokumentes begonnen werden soll: <page/>. Sehen Sie sich das XML-Dokument an! Parallel hierzu erweitern wir nun unser XSL-Sytelsheet:

Example 7.4. helloworld2html.xsl mit Template

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="page">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title></title>
</head>
<body>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Wenn wir nun bereits an dieser Stelle unser Zieldokument generieren lassen würden, so würden wir folgende Ausgabe erhalten:

Example 7.5. Das generierte Zieldokument ohne weiteren Inhalte

<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title></title>
</head>
<body>
</body>
</html>

Dies entspricht im Allgemeinen einem standardmässigen und gültigen XHTML-Dokument. Leider lässt sich mit so einem Dokument ohne Inhalt aber nicht allzuviel anstellen. Deshalb setzen wir nun die Inhalte aus unserem XML-Dokument an die gewünschten Positionen innerhalb des XHTML-Dokuments. Um dies zu erreichen, verwendet man die XSL-Anweisung <xsl:value-of select="[Pfad]">. Dabei bestimmt [Pfad] den Pfad zu einem Knoten (Element, Attribut) innerhalb des XML-Dokuments dessen Inhalt an die Stelle platziert werden soll, an der das Element <xsl:value-of/> im XSLT-Stylesheet steht. Da jedes XML-Dokument eine Baumstruktur darstellt, kann mit dieser Pfadangabe jedes Element eindeutig bezeichnet werden. Die Syntax, mit der ein Knoten in einem XML-Dokument identifziert werden kann, wird durch die Spezifikation XPath bestimmt, die ebenfalls vom W3C festgelegt wurde. Eine sehr gute Einführung zu dieser Sprache können Sie auf folgender Website erhalten: http://www.w3schools.com/xpath/default.asp. Ändern Sie Ihr XSL-Stylesheet nun folgendermaßen ab:

Example 7.6. helloworld2html.xsl mit Value-Of-Anweisungen

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="page">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>
      <xsl:value-of select="title"/>
   </title>
</head>
<body>
   <xsl:value-of select="content/header"/>
   <br/>
   <xsl:value-of select="content/text"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Wenn wir nun unser XHTML-Dokument anhand unseres XSLT_Stylesheets erstellen lassen würden, so würden wir folgende, vollständige Ausgabe erhalten:

Example 7.7. Das generierte Zieldokument mit Inhalten

<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>Tutorial 1</title>
</head>
<body>
   Hello World!
   <br/>
   Das ist ein beliebiger Text
</body>
</html>

Die Inhalte unserer XML-Datei wurden also entsprechend unseren Angaben in das XHTML-Dokument eingetragen. Um das Dokument nun auch betrachten zu können, also umzuwandeln, müssen wir es nur noch in der sitemap.xmap registrieren, wie im folgenden Abschnitt erklärt wird.

4. Die Sitemap anpassen

Die Datei sitemap.xmap ist die zentrale Datei, in der alle Komponenten – wie z.B. Generatoren, Transformatoren oder Verweise - von Cocoon registriert werden. Um nun unser Dokument über einen Browser aufrufen zu können, müssen wir Cocoon mitteilen, beim Aufruf welcher URL es die Ausführung beginnen soll. Cocoon benötigt hierfür folgende vier Informationen:

  • Welches XML-Dokument soll verwendet werden?

  • Welches XSL-Dokument soll für die Umwandlung verwendet werden?

  • Auf welche URL soll reagiert werden?

  • Welcher Dokumententyp soll zurückgeliefert werden?

Erstellen Sie hierfür eine sogenannte Sub-Sitemap mit dem Namen sitemap.xmap im Verzeichnis helloworld und fügen Sie dieser Datei folgenden Inhalt hinzu:

Example 7.8. Die Sub-Sitemap

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:pipelines>
      <map:pipeline>
         <map:match pattern="index.html">
            <map:generate type="file" src="xml/helloworld.xml"/>
            <map:transform type="xslt" src="stylesheets/helloworld2html.xsl"/>
            <map:serialize type="html"/>
         </map:match>
      </map:pipeline>
   </map:pipelines>

</map:sitemap>

In dieser Sitemap wurde mit dem Element <map:match/> festgelegt, dass alle Aufrufe der Form http://localhost:8080/cocoon/helloworld/index.html bewirken, dass der Rumpf ausgeführt wird. Innerhalb des Rumpfes wird zunächst definiert, dass das XML-Dokument helloworld.xml mit Hilfe eines Generators eingelesen und in einen SAX-Stream gewandelt werden soll. Danach wird der SAX-Stream unter Berücksichtigung der Vorgaben aus dem Dokument helloworld2html.xsl mit dem XSLTransformer in ein XHTML transformiert und anschließend mit Hilfe des HTMLSerializers ausgegeben.

Cocoon mountet, d.h.es ruft die Sub-Sitemap automatisch auf, sobald die entsprechende Sub-Applikation über die URL angesprochen wird. In unserem Fall lautet der Name der Sub-Applikation helloworld. Cocoon sucht also im Verzeichnis helloworld automatisch nach einer Datei sitemap.xmap und führt die darin definierten Anweisungen aus.

Note

Bitte beachten Sie, dass Ihr ServletContainer - z.B. Tomcat - nicht neu gestartet werden muss, wenn Sie neue Dokumente erstellt und in der sitemap.xmap registriert haben. Cocoon erkennt automatisch, ob ein Dokument verändert wurde und liest es neu ein, falls notwendig. Dies stellt einen enormen Vorteil gegenüber anderen Systemen, wie z.B. Servlets dar. Leider gilt das aber nicht für alle Änderungen, wie wir später noch sehen werden.

Nachdem Sie nun alle Änderungen an der Datei sitemap.xmap vorgenommen und diese gespeichert haben, können Sie Ihre erste kleine Cocoon-Applikation testen, indem Sie in Ihrem Browser folgende URI aufrufen: http://localhost:8080/cocoon/helloworld/index.html. Herzlichen Glückwunsch!

Probieren Sie anschließend doch einfach, Ihr XML-Dokument und XSLT-Stylesheet um einige Feinheiten zu erweitern. So können Sie die nun erworbenen Kenntnisse festigen.

Chapter 8. Tutorial 2 - Ein einfaches Formular

Fehler in diesem Kapitel melden. Danke!

In diesem Tutorial wollen wir uns mit dem einfachen Entgegennehmen und Wiederausgeben von Werten durch Cocoon über ein XHTML-Formular mit Hilfe eines XSLT-Stylesheets befassen. Ziel soll es sein, zu lernen, wie innerhalb eines XSL-Dokumentes auf Request-Parameter zugegriffen und diese anschließend in ein XML-Dokument eingebunden werden können. Wir erstellen uns hierfür aus einem vorgegebenen XSL-Dokument eine XHTML-Datei, wie in Tutorial 1 beschrieben. Mit dem Unterschied, dass das XSL-Dokument ein XHTML-Formular enthält und keine Werte aus einer XML-Datei liest. Das Formular enthält ein einziges Textfeld, in das der User einen beliebigen Wert eingeben kann. Dieser wird nach dem Absenden auf der gleichen Seite wieder ausgegeben. In der nachfolgenden Abbildung können Sie sehen, was auf der Website geschehen soll, wenn auf Submit geklickt wurde.

Figure 8.1. Der Abblauf der Anwendung

Der Abblauf der Anwendung

1. Aktivieren der Verarbeitung von Request-Parametern

Standardmäßig ist bei Cocoon die Verarbeitung von Request-Parametern ausgeschalten. D.h., dass diese innerhalb eines XSLT-Sytelesheets nicht zur Verfügung stehen. Um die Durchreichung von Request-Parametern in das XSLT-Stylesheet zu aktivieren, erstellen Sie zunächst eine Sup-Applikation, indem Sie ein Unterverzeichnis formular innerhalb von cocoon erzeugen und anschließend eine Datei mit dem Namen sitemap.xmap darin anlegen. Fügen Sie dieser Datei anschließend folgenden Inhalt hinzu:

Example 8.1. Die Sub-Sitemap sitemap.xmap

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

<map:components>
   <map:transformers>
      <map:transformer name="xslt" src="org.apache.cocoon.transformation.TraxTransformer">
         <use-request-parameters>true</use-request-parameters>
         <use-browser-capabilities-db>false</use-browser-capabilities-db>
      </map:transformer>
   </map:transformers>
</map:components>

<map:pipelines>

</map:pipelines>

</map:sitemap>

Mit dem Registrieren des TraxTransformers in der Sub-Sitemap wird die Definition aus der Main-Sitemap im Cocoon-Wurzelverzeichnis überschrieben. Im Unterschied zur Definition aus der Main-Sitemap wird hier die Konfiguration <use-request-parameters>true</use-request-parameters> verwendet, die bewirkt, dass innerhalb eines jeden XSLT-Stylesheets, welches mit Hilfe dieses Transformers verarbeitet wird, alle Request-Parameter automatisch als Stylesheet-Variablen zur Verfügung gestellt werden. Falls Sie keine solche generelle Konfiguration zulassen möchten, können Sie alternativ den XSLTTransformer bei Verwendung innerhalb des Match-Bereichs durch den gleichnamigen Sitemap-Parameter konfigurieren, wie im nachfolgenden Listing zu sehen ist:

Example 8.2. Konfigurieren bei Verwendung

<map:match ...>
   <map:generate ...>
      <map:transform type="xslt">
         <map:parameter name="use-request-parameters" value="true" />
      </map:transform>
   <map:serialize ...>
</map:match>

Letztere Konfigurationsmöglichkeit hat den Vorteil, dass Sie für jede Transformation einzeln entscheiden können, ob Sie die Request-Parameter im jeweiligen XSLT-Stylesheet zur Verfügung stellen möchten oder nicht. Der Nachteil dieser Methode ist, dass Sie möglicherweise diese Einstellung an vielen verschiedenen Stellen in Ihrer Sitemap vornehmen müssen.

Eine weitere Möglichkeit besteht darin, zwei XSLTTransformer mit unterschiedlichen Namen zu definieren, wobei bei einem die Verwendung von Request-Parametern erlaubt ist und beim anderen nicht. So können Sie immer in der jeweiligen Pipeline entscheiden, welche Konfiguration des XSLTTransformers Sie verwenden möchten, ohne zusätzliche Parameter übergeben zu müssen.

Example 8.3. Zwei XSLTTransformer unterschiedlich konfiguriert

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

<map:components>
   <map:transformers>
      <map:transformer name="xslt" src="org.apache.cocoon.transformation.TraxTransformer">
         <use-request-parameters>false</use-request-parameters>
         <use-browser-capabilities-db>false</use-browser-capabilities-db>
      </map:transformer>
      <map:transformer name="xslt-with-params" src="org.apache.cocoon.transformation.TraxTransformer">
         <use-request-parameters>true</use-request-parameters>
         <use-browser-capabilities-db>false</use-browser-capabilities-db>
      </map:transformer>
   </map:transformers>
</map:components>

<map:pipelines>

</map:pipelines>

</map:sitemap>

2. Erstellen der XML- und XSLT-Datei

Wechseln Sie nun in das Verzeichnis cocoon/formular. Erstellen Sie hier nachfolgend ein XSLT-Stylesheet mit dem Namen form.xsl und fügen Sie dieser Datei folgenden Inhalt hinzu:

Example 8.4. Die Datei form.xsl

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:param name="header"/>

<xsl:template match="page">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title>
         <xsl:value-of select="title"/>
      </title>
   </head>
   <body>
      <p>Ueberschrift: <b><xsl:value-of select="$header"/></b></p>
      <p>Bitte geben Sie eine Ueberschrift fuer diese Seite an:</p>
      <form action="form.html">
      <div>
         <input type="text" name="header"/>
         <input type="submit" />
      </div>
      </form>
   </body>
</html>
</xsl:template>

</xsl:stylesheet>

Als wichtigster Punkt in diesem XSLT-Stylesheet ist die Definition des Parameters <xsl:param name="header"/> im oberen Bereich des Stylesheets anzusehen. Wenn Sie die entsprechende Konfiguration durchgeführt haben, stellt Ihnen Cocoon alle Request-Parameter innerhalb eines XSLT-Stylesheets zur Vefügung. Welchen Parameter sie letzendlich aber benötigen, geben Sie dadurch an, indem Sie einen XSLT-Parameter direkt als Kindelement von <xsl:stylesheet/> definieren, der den selben Namen besitzt, wie der korrespondierende Request-Parameter. Der Definierte XSLT-Parameter enthält anschließend den Wert, den auch der zugehörige Request-Parameter besitzt.

Nachdem Sie die Datei form.xsl erstellt haben, erzeugen Sie im selben Verzeichnis eine weitere Datei mit dem Namen form.xml. Dabei handelt es sich um ein einfaches XML-Dokument, das lediglich den Titel der Seite bestimmen soll. Fügen Sie dieser Datei deshalb folgenden Inhalt hinzu:

Example 8.5. Die Datei form.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<page>
   <title>Tutorial 2</title>
</page>

Innerhalb des XSLT-Stylesheets wird der Titel aus diesem XML-Dokument ausgelesen und im Header des XHTML-Zieldokuments platziert.

3. Erstellen der Pipeline

Als letzer Punkt müssen letztendlich noch die Verarbeitungsschritte festgelegt werden, durch welche die Dokumente zum Zieldokument hin verarbeitet werden sollen. Fügen Sie hierzu in Ihrer Datei sitemap.xmap innerhalb des Elements <map:pipelines/> folgende Pipeline hinzu:

Example 8.6. Verarbeiten der Dokumente durch eine Pipeline

<map:pipeline>
   <map:match pattern="form.html">
      <map:generate type="file" src="form.xml"/>
      <map:transform type="xslt-with-params" src="form.xsl"/>
      <map:serialize type="html"/>
   </map:match>
</map:pipeline>

In der gezeigten Pipeline wird definiert, dass bei einem Match auf form.html zunächst das Dokument form.xml in einen SAX-Stream verwandelt und anschließend dieser Stream durch das XSLT-Stylesheet form.xsl entsprechend transformiert werden soll. Am Ende wird das Ergebnis durch den HTML-Serializer an den Client ausgegeben.

Um das Ergebnis Ihrer Arbeit letztendlich testen zu können, müssen Sie lediglich die URI http://localhost:8080/cocoon/formular/form.html aufrufen.

Chapter 9. Tutorial 3 - Logik mit Hilfe von XSP integrieren

Fehler in diesem Kapitel melden. Danke!

In diesem Tutorial geht es darum, Logik in eine Cocoon-Anwendung zu integrieren. Dabei beschränken wir uns zunächst auf die Verwendung von Extensible Server Pages (XSP). Mit Hilfe von XSP wollen wir zwei Request-Parameter, die über ein Formular versendet wurden, entgegennehmen, diese Addieren und das Ergebnis wieder ausgeben. Ein Validierung, ob es sich bei den eingegebenen Werten um echte Zahlen handelt oder nicht, lassen wir aus Gründen der Übersichtlichkeit außen vor. Falls Sie sich an dieser Stelle unter dem Begriff "XSP" überhaupt nichts vorstellen können, würde ich Ihnen dringend empfehlen, zuerst das Kapitel über XSP durchzulesen. Hier wird erklärt, was XSP ist und wie es funktioniert.

1. Erstellen der notwendigen Ressourcen

Erstellen Sie als erstes wieder eine Sub-Applikation, indem Sie einfach ein neues Verzeichnis mit dem Namen tutorial3 innerhalb von cocoon erzeugen und darin eine leere Datei mit dem Namen sitemap.xmap erstellen.

Als nächstes benötigen Sie für dieses Tutorial zwei weitere Dateien: Zum einen eine XML-Datei, die den Content und die XSP-Logik beinhaltet und zum anderen ein XSLT-Stylesheet, welches das XML-Dokument wie gewohnt als XHTML-Ausgabe aufbereitet. Erstellen wir also zuerst eine XSP-Datei, die zunächst noch eine ganz normale XML-Datei ohne jeglichen "Schnickschnack" sein wird. Öffnen Sie hierzu Ihren Editor, fügen Sie nachfolgende Zeilen ein und speichern Sie die Datei unter dem Namen logic.xsp innerhalb von tutorial3 ab:

Example 9.1. Die Datei logic.xsp

<?xml version="1.0" encoding="ISO-8859-1"?>
<page>
   <title>Tutorial 3</title>
   <content>
      <header>Addierer</header>
      <message>Das Ergenis lautet</message>
   </content>
</page>

Diese gewöhnliche XML-Datei definiert lediglich den Titel, die Überschrift und einen Hinweis für die Seite, sonst nichts. Noch nicht!

Erstellen Sie als nächstes ein XSLT-Stylesheet, das zuvor erstellte XML-Dokument logic.xsp entgegen nimmt und in XHTML umwandelt. Das entsprechende XSLT-Stylesheet sollte unter dem Namen layout.xsl im Verzeichnis tutorial3 gespeichert werden und folgenden Inhalt besitzen:

Example 9.2. Die Datei layout.xsl

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="page">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title><xsl:value-of select="title"/></title>
   </head>
   <body>
      <h1><xsl:value-of select="content/header"/></h1>

      <form action="tutorial3">
         <p>
            <input type="text" name="addend1" value="0"/>
            <b> + </b>
            <input type="text" name="addend2" value="0"/>
         </p>
         <p>
            <input type="submit"/>
         </p>
      </form>

      <p>
         <xsl:value-of select="content/message"/> =
      </p>
      <p>
         <xsl:value-of select="content/text"/>
      </p>
   </body>
</html>
</xsl:template>

</xsl:stylesheet>

Das XSLT-Stylesheet definiert ein XHTML-Formular mit zwei Eingabefeldern mit den Namen addend1 und addend2. In diese Eingabefelder können später die beiden Summanden der Addition eingegeben werden. Durch das Attribut value=0 werden die beiden Summanden standardmässig immer auf den Wert 0 gesetzt, wenn die Seite das erste mal betreten wird. Das XSLT-Stylesheet ist nun soweit erstellt und wäre so auch voll einsetzbar. Was es jedoch ausgegeben würde, hätte wenig mit einer Addtion bzw. XSP zu tun: Ein einfaches Formular, darunter einen Hinweistext. Es würde sich nichteinmal etwas "rühren", wenn wir auf den Submit-Button klicken. Um dies zu ändern, machen wir einige kleine Anpassungen an der XSP-Datei.

2. XSP-Logik integrieren

An dieser Stelle sollten Sie sich nun fragen, was alles geändert werden muss:

  • Wie kommt man an die Parameter addend1 und addend2, die in das Formular zuvor eingegeben wurden?

  • Wie und wo können die beiden Parameter addiert werden?

  • Wie und wo kann das Ergebnis wieder ausgegeben werden und zwar so, dass es auf der XHTML-Seite angezeigt wird?

Beantworten wir diese Fragen in der Reihenfolge, in der sie gestellt wurden. Die gesamte Logik wird in die XSP-Datei gelegt. Um die Datei logic.xsp nun in eine 100%ige XSP-Datei umzuwandeln, müssen wir einige Änderungen an ihr vornehmen. Fügen Sie zunächst ein neues Wurzelelement <xsp:page/> ein, dass das "alte" Wurzelelement <page/> einschließt, wie nachfolgend gezeigt:

Example 9.3. Einbinden des XSP-Root-Elements

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsp:page language="java" xmlns:xsp="http://apache.org/xsp">

<page>
   <title>Tutorial 3</title>
   <content>
      <header>Addierer</header>
      <message>Das Ergebnis lautet</message>
   </content>
</page>

</xsp:page>

Mit diesen wenigen Zeilen haben wir nun bereits aus unserer XML-Datei ein XSP-Dokument gemacht, dass auch von jedem XSP-Generator verstanden werden würde. Wir könnten in dieser Datei nun jede beliebige Art von Java-Logik platzieren, solange wir die Eigenschaften berücksichtigen, die ein XSP-Dokument aufweisen muss. Dass es Java-Logik sein muss, haben wir mit language=java festgelegt. Daneben ist darauf zu achten, dass alle XSP-Elemente über das Präfix xsp an den Namensraum http://apache.org/xsp gebunden sein müssen. Die wichtigste XSP-Eigenschaft aber, die Sie nie vergessen dürfen, ist: Eine XSP-Datei ist auch ein XML-Dokument und muss deshalb allen Regeln entsprechen, die für ein wohlgeformtes XML-Dokument gelten müssen. Falls Sie sich nicht mehr an diese Regeln erinnern können, schlagen Sie bitte im Kapitel XML nach.

Solange wir aber keinen Zugriff auf unsere beiden Request-Parameter addend1 und addend2 haben, können wir auch keine Addition ausführen. Um innerhalb eines XSP-Dokumentes Zugriff auf die Parameter des Requests zu erhalten, muss zuvor immer der Namensraum http://apache.org/xsp/request/2.0 eingebunden werden. Dieser wird standardmässig dem Präfix xsp-request zugeordnet. Halten Sie sich unbedingt an diese Regel, da Sie vielleicht irgendwann Ihren Code weitergeben möchten und andere sich dadurch schnell zurechtfinden. Die Einbindung des Namensraum hat zur Folge, dass der XSP-Generator zusätzliche Funktionalitäten zur Verfügung stellt. Hatten wir zuvor nur die Möglichkeit Logik jeglicher Art zu erstellen, wird diese nun um den Zugriff auf alle Request-Parameter erweitert. Fügen wir also nun noch den Namensraum für xsp-request der XSP-Datei logic.xsp hinzu:

Example 9.4. Der XSP-Request-Namensraum

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsp:page language="java" xmlns:xsp="http://apache.org/xsp"
   xmlns:xsp-request="http://apache.org/xsp/request/2.0">

   <page>
      <title>Tutorial 3</title>
      <content>
         <header>Addierer</header>
         <message>Das Ergebnis lautet</message>
      </content>
   </page>

</xsp:page>

Nun ist die XSP-Datei soweit vorbereitet, dass die ersten Zeilen Logik eingefügt werden können. Als erstes werden endlich die Parameter addend1 und addend2 aus dem Request geholt. Dafür verwenden wir das Element <xsp-request:get-parameter/>. Zusätzlich definieren wir eine Methode, die diese Werte von String nach Integer konvertiert, summiert und anschließend das Ergebnis zurückliefert. Beachten Sie, dass die Zuweisung der Request-Parameter innerhalb der Methode erfolgt. Dadurch wird gewährleistet, dass addend1 und addend2 innerhalb dieser Methode sichtbar sind.

Example 9.5. Zugriff auf den Request innerhalb einer XSP-Datei

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsp:page language="java" xmlns:xsp="http://apache.org/xsp"
   xmlns:xsp-request="http://apache.org/xsp/request/2.0">
    
   <xsp:logic>

   /**
    * Diese Methode konvertiert die beiden Request-Parameter nach int,
    * addiert diese und liefert anschliessend die Summe der beiden zurueck.
    * @return Summe der Addition addend1 und addend2.
    */
   public int add() {

      // Hier holen wird die Werte aus dem Request
      String addend1 = <xsp-request:get-parameter name="addend1"/>;
      String addend2 = <xsp-request:get-parameter name="addend2"/>;

      int a = 0;
      int b = 0;

      // Testen, ob addend1 vorhanden ist
      if(addend1 != null)
         a = Integer.parseInt(addend1);
        
      // Testen, ob addend2 vorhanden ist
      if(addend2 != null)
         b = Integer.parseInt(addend2);
        
      // Beide Zahlen addieren
      int sum = a + b;
        
      // Summe zurückliefern
      return sum;
   }

   </xsp:logic>

   <page>
      <title>Tutorial 3</title>
      <content>
         <header>Addierer</header>
         <message>Das Ergebnis lautet</message>
      </content>
   </page>

</xsp:page>

Note

Logik wird immer innerhalb des Elements <xsp:logic/> definiert!

Wir haben nun also bereits die ersten beiden Fragen beantwortet. Wir wissen, wie wir Zugriff auf unsere Request-Parameter erhalten und wie/wo wir diese addieren können. Die letzte, noch ausstehende Frage lautet: Wie kann ich das Ergebnis nun ausgeben? Dafür müssen wir nur noch zwei Schritte erledigen: Zum einen das Ergebnis in das XML-Dokument schreiben und zum anderen über das XSLT-Stylesheet wieder auslesen. Schreiben wir zuerst das Ergebnis unserer Addition in ein neues Element in unsere XSP-Datei:

Example 9.6. Einbetten der Summation

...
<page>
   <title>Tutorial 3</title>
   <content>
      <header>Addierer</header>
      <message>Das Ergebnis lautet</message>
      <sum><xsp:expr>add()</xsp:expr></sum>
   </content>
</page>

</xsp:page>

Note

Ausgaben in das XML-Dokument werden immer innerhalb des Elements <xsp:expr/> angegeben!

In diesem XSP-Dokument wurde also ein neues Element <sum/> ertsellt, das später das Ergebnis der Addition enthalten wird. Durch das Element <xsp:expr/> wird dem XSP-Generator mitgeteilt, dass er genau an diese Stelle den Rückgabewert der Methode add() schreiben soll.

Als nächsten Schritt müssen wir unser Ergebnis irgendwo in unser XHTML-Dokument ausgeben. Hierzu bearbeiten wir auch unser XSLT-Stylesheet ein letztes mal:

Example 9.7. Ausgabe der Summation

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="page">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title><xsl:value-of select="title"/></title>
   </head>
   <body>
      <h1><xsl:value-of select="content/header"/></h1>

      <form action="tutorial3">
         <p>
            <input type="text" name="addend1" value="0"/>
            <b> + </b>
            <input type="text" name="addend2" value="0"/>
         </p>
         <p>
            <input type="submit"/>
         </p>
      </form>

      <p>
         <xsl:value-of select="content/message"/> =
         <b><xsl:value-of select="content/sum"/></b>
      </p>
      <p>
         <xsl:value-of select="content/text"/>
      </p>
   </body>
</html>
</xsl:template>

</xsl:stylesheet>

3. Registrieren in der Sitemap

Wie immer, müssen auch in diesem Fall alle Dokumente, die für diese Anwendung generiert und weiterverarbeitet werden sollen, in der Datei sitemap.xmap registriert werden. Fügen Sie hierfür die Folgenden Zeilen in die Sitemap ein:

Example 9.8. Die Datei sitemap.xmap

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

   <map:components>
      <map:generators>
         <map:generator name="serverpages" src="org.apache.cocoon.generation.ServerPagesGenerator"/>
      </map:generators>
   </map:components>

   <map:pipelines>
      <map:pipeline>
         <map:match pattern="index.html">
            <map:generate type="serverpages" src="logic.xsp"/>
            <map:transform type="xslt" src="style.xsl"/>
            <map:serialize type="html"/>
         </map:match>
      </map:pipeline>
   </map:pipelines>
</map:sitemap>

Note

Ein XSP-Dokument muss immer durch einen XSP-Generator eingelesen werden, um den eingebetteten Code interpretieren zu können.

In der Sitemap wird also festgelegt, dass beim Aufruf der URI http://localhost:8080/cocoon/index.html ein XSP-Generator verwendet werden soll, um die Datei logic.xsp einzulesen, zu parsen und in einen SAX-Stream umzuwandeln, damit der XSLT-Transformer die XML-Struktur weiterverarbeiten kann. Der XSLT-Transformer wendet diese XML-Struktur anschließend auf das Stylesheet layout.xsl an und gibt zu guter Letzt das Resultat per HTMLSerializer als HTML bzw. XHTML aus.

Chapter 10. Tutorial 4 - Eine eigene Action programmieren

Fehler in diesem Kapitel melden. Danke!

Eine Action ist - neben Control Flow - die beste Möglichkeit, Logik in die Applikation zu packen. Sie ist eine Java-Klasse, die die gesamte Mächtigkeit dieser Sprache nutzen kann und wird verwendet, um komplexe Aufgaben zu erledigen und eine grosse Komponentenorientierung zu realisieren. Mit XSP wäre dieses nur mühsam umzusetzen. Eine, einmal programmierte Action kann in jeder weiteren Cocoon-Applikation wiederverwendet werden, ohne große Anpassungen an den Schnittstellen selbst machen zu müssen.

In diesem Tutorial wollen wir eine Action erstellen, die einfach nur das aktuelle Datum berechnet und wieder zurückgibt, mehr nicht.

Bevor allerdings mit dem Erstellen der Dateien begonnen werden kann, auch hier - wie in allen vorangegangenen Tutorials - der Hinweis, dass alle Dateien - mit Ausnahme der Action-Klasse - in einer eigenen Sub-Applikation abgelegt werden sollen. Erstellen Sie hierfür einfach ein Unterverzeichnis mit dem Namen tutorial4 innerhalb von cocoon.

1. Erstellen der Action-Klasse

Wir wissen bereits aus dem Kapitel über Actions, dass eine Action immer einen der beiden nachfolgenden Werte zurück liefern muss:

  • Null

  • Java-Map

Wird Null zurückgeliefert, so wird der Rumpf der Action nicht ausgeführt. Soll hingegen der Rumpf der Action ausgeführt werden, muss eine Java-Map zurück geliefert werden. Es ist nicht zwingend erforderlich, dass die Java-Map Name-Wert-Paare enthält. Sie darf nur nicht Null sein.

Note

Die, von der Action zurückgelieferte Java-Map enthält nicht die Werte, die später auf dem Ausgabedokument angezeigt werden sollen. Es handelt sich hierbei lediglich um Steuerwerte für die Sitemap. So wäre es denkbar, dass die Action anhand bestimmter Kriterien einen Namen erzeugt und als Parameter zurückliefert, der ein bestimmtes XML-Dokument benennt, das wiederum ein nachfolgender Generator einlesen soll. Sehen Sie sich hierzu das nachfolgende Listing an.

Example 10.1. Verwenden einer Action-Variable

<map:act type="getweekday">
   <map:generate type="file" name="{weekday}.xml" />
   <map:serialize type="xml" />
</map:act>

In diesem unvollständigen Beispiel wird also beim Aufruf der Pipeline die Action mit dem Namen getweekday ausgeführt, welche den aktuellen Wochentag bestimmt und dessen Namen unter dem Schlüssel weekday in der Java-Map ablegt. Je nachdem, welcher Wochentag gerade ist, wird anschließend durch den Generator z.B. die Datei saturday.xml, sunday.xml, monday.xml, usw. aufgerufen. Würde innerhalb der Action ein Fehler auftreten, so würde diese den Wert Null zurück liefern, was zur Folge haben würde, dass der Rumpf von <map:act/> nicht ausgeführt wird.

Neben den bereits genannten Rückgabewerten muss eine Action innerhalb von Cocoon noch weitere Regeln erfüllen, damit sie eingesetzt werden kann. Sie muss z.B. genau eines der nachfolgenen abstrakten Basisklassen implementieren:

  • org.apache.cocoon.acting.AbstractAction

  • org.apache.cocoon.acting.AcbstractConfigurableAction

  • org.apache.cocoon.acting.AbstractComplementaryConfigurableAction

  • org.apache.cocoon.acting.AbstractDatabaseAction

  • org.apache.cocoon.acting.AbstractValidatorAction

In diesem Tutorial benützen wir lediglich die abstrakte Klasse AbstractAction, da diese am schnellsten zu implementieren ist. Alle anderen Abstract-Actions haben entweder einen erweiterten oder einen speziellen Funktionsumfang, der an dieser Stelle nicht benötigt wird. Z.B. kann eine AbstactConfigurableAction durch externe Konfigurationsdateien parametrisiert werden. Weiterführende Informationen zu den einzelnen abstrakten Actions kann in der API-Doc eingesehen werden: http://cocoon.apache.org/2.1/apidocs/org/apache/cocoon/acting/package-summary.html.

Als letzte, wichtige Regel sollten Sie beachten, dass sich jede Action innerhalb des Klassenpfades befinden muss, wie alle übrigen Java-Klassen auch. Dies wäre z.B. WEB-INF/classes oder aber auch WEB-INF/lib. Für diejenigen Leser, die bereits Erfahrung in der Servlet-Programmierung besitzen, ist dies sicherlich nicht verwunderlich, da auch Servlets hier abgelegt werden.

Nachdem wir also festgelegt haben, welche Eigenschaften eine Action zu erfüllen hat, machen wir uns nun endlich daran und erstellen unsere erste Action, die das heutige Datum errechnet und zurückgibt. Dafür legen wir innerhalb von WEB-INF/classes zuerst folgende Ordnertruktur an: com/logabit/cocoon/acting. Natürlich kann an dieser Stelle jede beliebige andere Struktur angelegt und verwendet werden. Ich werde mich aber in den späteren Konfigurationseinstellungen, sowie den Package-Angaben auf diesen Pfad beziehen. Bitte berücksichtigen Sie dies, wenn Sie einen anderen Pfad verwenden. Innerhalb des erzeugten Verzeichnisses legen wir nun eine Datei mit dem Namen ExampleDateAction.java an. Öffnen Sie anschließend diese Datei und fügen sie folgenden Code ein:

Example 10.2. Die Datei ExampleDateAction.java

package com.logabit.cocoon.acting;

import org.apache.cocoon.acting.AbstractAction;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import java.util.Map;
import java.util.HashMap;

public class ExampleDateAction extends AbstractAction {

   public Map act (Redirector redirector, 
      SourceResolver resolver, Map objectModel, 
      String source, Parameters params) {
   }
}

Diese Klasse ist so natürlich noch nicht kompilierbar, da die Methode act() noch keinen Rückgabewert enthält. Diesen wollen wir erst später einfügen. Sehen wir uns zuerst an, aus welchen Teilen diese Klasse besteht:

Example 10.3. Der Import-Bereich

package com.logabit.cocoon.acting;

import org.apache.cocoon.acting.AbstractAction;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import java.util.Map;
import java.util.HashMap;

In diesem Teil wird zum einen das Package definiert und zum anderen werden hier alle notwendigen Klassen importiert.

Example 10.4. Der Klassenrumpf

public class ExampleDateAction extends AbstractAction {

   public Map act (Redirector redirector, 
      SourceResolver resolver, Map objectModel, 
      String source, Parameters params) {
   }
}

Hier wird die Methode act() definiert, welche noch implementiert werden muss. Sie wird von Cocoon aufgerufen und kann in etwa mit den Methoden doPost() und doGet() bei Servlets oder perform() bei Struts verglichen werden. Der Methode werden vom Aufrufer eine menge Parameter mit übergeben, welche folgende Bedeutung haben:

  • redirector - Hierbei handelt es sich um ein Objekt, das es erlaubt, dass die Action auf eine andere Ressource weiterleitet.

  • resolver - Dieses Objekt ist äußerst hilfreich wenn Sie Ressourcen, wie z.B. lokale Dateien laden möchten. Das Resolver-Objekt kann mit allen unter Cocoon erlaubten Protokollen umgehen.

  • objectModel - Diese Java-Map enthält einige wichtige Objekte, die den Cocoon-Context beschreiben. Unter anderem beinhaltet es das Request-Objekt. Um das Request-Objekt daraus zu laden ist es am besten, Sie verwenden den sogenannten ObjectModelHelper: http://cocoon.apache.org/2.1/apidocs/org/apache/cocoon/environment/ObjectModelHelper.html

  • source - Dieser String enthält den Wert, der durch das optionale Attribut src im Element <map:act/> angegeben wurde.

  • parameters - Eine Liste von Parametern, welche der Action durch das Element <map:paramener name="" value=""/> im Rumpf übergeben werden kann.

Nachdem wir unsere Action mit leerer act()-Methode angelegt haben, müssen wir nun deren Rumpf definieren. An diese Stelle kommt also die eigentliche Logik. Als erstes erstellen wir "javaüblich" ein Date-Objekt und instanziieren dieses. Fügen Sie hierfür die folgenden, hervorgehobenen Zeilen Ihrer Action hinzu:

Example 10.5. Das Date-Objekt erzeugen

...
import java.util.Date;

public class ExampleDateAction extends AbstractAction {

   public Map act (Redirector redirector, 
      SourceResolver resolver, Map objectModel, 
      String source, Parameters params) {

      Date date = new Date();
   }
}

Das erstellen das Datumsobjektes dürfte für jeden Java-Entwickler kein Problem sein. Es macht aber durchaus Sinn, an dieser Stelle zu stoppen und sich die Frage zu stellen: "Wie bekomme ich dieses Datumsobjekt denn nun in meine Seite?". Wir wissen, dass es nicht mit dem Rückgabeobjekt Map geschehen kann, da diese Werte für die Benutzung innerhalb der Pipeline vorgesehen sind. Unter uns: Man könnte diese Werte natürlich auch über die Sitemap "durchschleifen" und auf dem Zieldokument ausgeben. Ich würde Ihnen aber in jedem Fall davon abraten, da Sie sich zum einen unnötige Arbeit aufhalsen und zum anderen als Ergebnis ein heilloses Durcheinander erhalten können. Na gut, aber wie bekommen wir sonst den Wert in unser Zieldokument, wenn nicht über diesen Weg?

Die Lösung ist das statische Objekt objectModel, das wir als Methodenparameter übergeben bekommen. Dieses Objekt enthält eine Referenz auf das Request-Objekt, das wir - wie unter Servlets gewohnt - benutzen können, um unsere Werte zu übergeben. Um das Request-Objekt zu erhalten, fügen wir also folgende Zeile ein:

Example 10.6. Zugriff auf den Request

...
Date date = new Date();
Request request = ObjectModelHelper.getRequest(objectModel);
...

Das objectModel ist eine Java-Map, in der alle notwendigen Objekte der Applikation abgelegt sind, die benötigt werden. Dadurch können Informationen zu den einzelnen Objekten innerhalb der Pipeline allen anderen Komponenten zur Verfügung gestellt werden. Es ist sozusagen eine zentrale Aufbewahrungsstelle für alle relevanten Objekte. Für den vereinfachten Zugriff verwenden wir den ObjectModelHelper, welcher für uns das entsprechende Objekt komfortabel aus dem objectModel extrahiert. Anschließend können wir das Date-Objekt unter einem bestimmten Namen in den Request-Scope legen, wie auch aus der Servlet-Programmerung bekannt:

Example 10.7. Date-Objekt in den Request-Scope legen

...
Request request = ObjectModelHelper.getRequest(objectModel);
request.setAttribute("date", date);
...

Das, was die Action zu leisten hat, würde sie nun auch erfüllen. Damit zum einen der Kompiler nicht mäckert und zum anderen die Abfolge in der Sitemap auch so ist, wie wir es uns erhoffen (ausführen des Rumpfes) müssen wir unserer Action noch eine Kleinigkeit hinzufügen. Zu Beginn dieses Tutorials haben wir definiert, dass eine Action immer einen der Werte Null oder Java-Map zurückliefern muss. Da wir möchten, dass unsere Action und die nachfolgenden Komponenten in jedem Fall ausgeführt werden, liefern wir hier einfach eine leere Map zurück:

Example 10.8. Zurückliefern einer leeren Java-Map

...
request.setAttribute("date", date);

Map sitemapParams = new HashMap();
return sitemapParams;
...

Das wars. Sie müssten nun eine Action der nachfolgenden Form besitzen. Nachdem Sie diese Action kompiliert haben, ist diese bereits einsetzbar.

Example 10.9. Die vollständige Action ExampleDateAction

package com.logabit.cocoon.acting;

import org.apache.cocoon.acting.AbstractAction;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import java.util.Map;
import java.util.HashMap;
import java.util.Date;

public class ExampleDateAction extends AbstractAction {

   public Map act (Redirector redirector, 
      SourceResolver resolver, Map objectModel, 
      String source, Parameters params) {

      Date date = new Date();
      Request request = ObjectModelHelper.getRequest(objectModel);
      request.setAttribute("date", date);

      Map sitemapParams = new HashMap();
      return sitemapParams;
   }
}

2. Erstellen des Ausgabedokuments

Nachdem wir unsere Action erstellt haben, möchten wir natürlich überprüfen, ob diese auch funktioniert. Hierfür geben wir das erzeugte Datum auf einer HTML-Seite aus. Um dies realisieren zu können, müssen wir uns zuvor ein XSP-Dokument mit dem Namen date.jxt erstellen, welches sich im Verzeichnis tutorial4 befinden sollte. Dieses Dokument ist ein JX-Template, das später alle dynamischen Werte enthalten wird. In unserem Fall ist das natürlich etwas wenig, aber immerhin: Der Datumswert. Da wir das Date-Objekt in den Request gelegt bekommen, können wir es einfach mit JEXL von dort auch wieder auslesen und in das XML schreiben. JEXL ist eine spezielle Sprache, welche an die unter JSP bekannte Sprache JSTL angelehnt ist. Falls Sie mehr über JEXL und JX-Template erfahren möchten, sollten Sie die zugehörige Website besuchen: http://cocoon.apache.org/2.1/userdocs/flow/jxtemplate.html. Fügen Sie der Datei date.jxt nun folgende Zeilen hinzu:

Example 10.10. Die Datei date.jxt

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

<html xmlns:jxt="http://apache.org/cocoon/templates/jx/1.0">

<head>
   <title>ExampleDateAction</title>
</head>
<body>

   Die Action hat folgendes Datum erzeugt: ${request.getAttribute('date')}

</body>
</html>

Wie Sie sehen, wird in diesem JX-Template das zuvor durch die Action abgelegte Datums-Objekt einfach aus dem Request unter demselben Namen extrahiert und angezeigt. Das ist doch einfach, nicht wahr? Der Vollständiglkeit halber soll an dieser Stelle noch darauf hingewiesen werden, dass es unter Cocoon noch zahlreiche andere Möglichkeiten gibt, den Präsentationslayer zu erzeugen. Z.B. mit Hilfe einer XSP-Datei. Mir erscheint für dieses Beispiel allerdings der Weg über das JX-Template der pragmatischte zu sein. Experimentieren Sie!

3. Registrieren und Ausführen der Action

Der letzte Schritt der zu machen ist, damit unsere Action mit den entsprechenden Dokumenten zusammenarbeitet, ist das Registrieren dieser in der Sitemap. Erzeugen Sie hierfür innerhalb des Verzeichnisses tutorial4 eine Datei mit dem Namen sitemap.xmap und fügen Sie dieser folgende Zeilen hinzu:

Example 10.11. Die Sub-Sitemap sitemap.xmap

<?xml version="1.0" encoding="UTF-8"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

<map:components>
   <map:generators>
      <map:generator name="jxt" src="org.apache.cocoon.generation.JXTemplateGenerator"/>
   </map:generators>
   <map:actions>
      <map:action name="exampleDateAction" src="com.logabit.acting.ExampleDateAction"/>
   </map:actions>
</map:components>

<map:pipelines>
   <map:pipeline>
   
      <map:match pattern="date.html">
         <map:act type="exampleDateAction">
            <map:generate type="jxt" src="date.jxt"/>
            <map:serialize type="html"/>
         </map:act>
      </map:match>
      
   </map:pipeline>
</map:pipelines>

</map:sitemap>

Als erstes wird in der Pipeline neben dem JXTemplateGenerator, welcher für das Interpretieren des JX-Templates verantwortlich ist, auch unsere Action durch das Element <map.action/> registriert.

Für den Ablauf selbst legen wir eine neue Pipeline an, die als erstes die Action ausführt und anschließend das JX-template durch den JXTemplateGenerator aufruft. Zu guter Letzt wird das Zieldokument per HTMLSerializer an den Client versendet.

Nachdem Sie alle Dokumente gespeichert und/oder kompiliert haben, können Sie einen ersten Aufruf der Adresse http://localhost:8080/cocoon/tutorial4/date.html wagen. Wenn alles gut geht, wird Ihnen im Browser das aktuelle Datum angezeigt. Falls nicht, überprüfen Sie bitte alle Schritte, ob Sie nicht eine Kleinigkeit vergessen haben. Herzlichen Glückwunsch zu Ihrer ersten Cocoon-Action!