Linkwerk Logo

xsltdoc — Literate XSLT Programming based on Namespaces

Inhalt:

Einführung

Donald Knuth' Idee des Literate Programming wurde in den vergangenen Jahren bereits in viele Programmierszenarien, -sprachen usw. übertragen. Auch für SGML/XML wurde die Idee bereits mehrfach diskutiert (vgl. dazu auch die Cover Pages). Gemeinsam ist allen Ansätzen das Folgende:

Während der erste Punkt gewünscht, ja sogar eine zentrale Eigenschaft des Literate Programming ist, und der zweite Punkt üblich, ist der dritte Punkt in den meisten Fällen eine Notwendigkeit, die nicht gewünscht ist. Sie resultiert aus der Tatsache, dass ein Compiler oder Interpreter durch Dokumentation im Programmcode einen Fehler erzeugt. Ein Ansatz, dieses Problem zu lösen, besteht darin, Dokumentation in einer bestimmten Syntax innerhalb von Kommentaren der jeweiligen Programmiersprache unterzubringen.

Literate Programming in XSLT

Im Falle der Programmiersprache XSLT liegt eine besondere Situation vor, falls das Format der Dokumentation ebenfalls eine XML-Sprache ist (etwa im Fall von XHTML oder Docbook): Dann verwenden sowohl die Programmiersprache als auch das Dokumentationsformat die selbe Syntax – nämlich XML. Aus formaler XML-Sicht handelt es sich bei dem Inhalt einer derartigen Datei um nichts weiter als eine XML-Datei, die Elementtypen aus unterschiedlichen Namensräumen verwendet. Um solche Elementtypen auseinanderzuhalten, gibt es eine entsprechende Technik, genannt Namensräume in XML.

Das daraus abgeleitete Konzept des Literate XSLT Programming ist an folgendem Beispiel veranschaulicht:

HTML rendering of a XML instance
<xslt:stylesheet xmlns:xslt="http://www.w3.org/1999/XSL/Transform" version="1.0">
<doc:title xmlns:doc="http://www.linkwerk.com/namespaces/2005-02-03/xsltdoc/">
Some documentation ...
</doc:title>
<xslt:template match="*">
<doc:para xmlns:doc="http://www.linkwerk.com/namespaces/2005-02-03/xsltdoc/">
Some more documentation ...
</doc:para>
<xslt:apply-templates></xslt:apply-templates>
</xslt:template>
</xslt:stylesheet>

Die Dokumentation, hier in Elementen der fiktiven Typen title und para enthalten, ist an beliebigen Stellen im XSLT-Programmcode untergebracht. Die Elemente beider Welten sind durch Namensräume voneinander getrennt. Selbstverständlich ist zur Formatierung eine Software notwendig.

Bei dieser Vorgehensweise sind eine Reihe von Punkten, die im Folgenden diskutiert werden, zu beachten. Die Diskussion führt schließlich zu der Software, die die beschriebene Vorgehensweise implementiert.

Dokumentation innerhalb und außerhalb von Templates

Unterhalb des Wurzelelements eines XSLT-Programms sind beliebige Elemente eines fremden Namensraums zulässig, sofern der Namensraum-URI nicht leer ist. Diese Aussage stützt sich auf die entsprechende Festlegung am Ende von Abschnitt 2.2 der XSLT-1.0-Spezifikation (Englisch, Deutsch).

Anders sieht es bei Elementen innerhalb von Templates aus. Diese werden durch die XSLT-Engine als Teil der Ausgabe angesehen. Wünschenswert wäre jedoch die Ignorierung der Dokumentation beim Ablauf des XSLT-Programms. XSLT bietet eine Möglichkeit fremde Elemente innerhalb von Templates nicht als Teil der Ausgabe zu behandeln: Die Elemente müssen als Erweiterungselemente (Englisch, Deutsch) deklariert werden. Das folgende Listing zeigt wie das geht:

HTML rendering of a XML instance
<xslt:stylesheet xmlns:xslt="http://www.w3.org/1999/XSL/Transform" version="1.0" xslt:extension-element-prefixes="doc">
<doc:title xmlns:doc="http://www.linkwerk.com/namespaces/2005-02-03/xsltdoc/">
Some documentation ...
</doc:title>
<xslt:template match="*">
<doc:para xmlns:doc="http://www.linkwerk.com/namespaces/2005-02-03/xsltdoc/">
<xslt:fallback></xslt:fallback>
Some more documentation ...
</doc:para>
<xslt:apply-templates></xslt:apply-templates>
</xslt:template>
</xslt:stylesheet>

Auf den ersten Blick ist der Vorgang sehr einfach: Im Wurzelelement steht xslt:extension-element-prefixes="doc". Damit ist der doc-Namensraum als Erweiterungsnamensraum deklariert, alle entsprechenden Elemente werden nicht als Ausgabe interpretiert. Allerdings geht die XSLT-Engine nun davon aus, dass sie die Erweiterung implementieren müsste; da das für diesen Namensraum natürlich bei keiner Software der Fall ist, bricht die Verarbeitung ohne weitere Vorkehrungen mit einem Fehler ab. XSLT bietet jedoch einen Rückgriff an: Mit xslt:fallback kann der Programmierer einen Ersatz für nicht implementierte Erweiterungen anbieten. In diesem Fall ist xslt:fallback leer, was genau das Verhalten erzeugt, dass wir beim Ablauf des Programms für die eingebettete Dokumentation wünschen: Gar keins.

Zusammenfassung: Die Erläuterungen bis zu diesem Zeitpunkt geben uns die Möglichkeit, Dokumentation in ein XSLT-Programm einzubauen; wobei dies auf der Ebene unmittelbar unter dem Wurzelelement einfach so möglich ist, während für Dokumentation innerhalb von Templates der Namensraum als Erweiterung deklariert und jedes Dokumentationselement einen xslt:fallback besitzen muss.

Formate und Namensraum-URI für Dokumentation

Der hier vorgestellte Ansatz ist nicht auf ein Dokumentationsformat festgelegt. Es lassen sich prinzipiell Elemente beliebiger Typen ausgeben. Ein beliebtes Format ist XHTML, nicht zuletzt wegen seiner weiten Verbreitung. Aber auch Docbook käme in Frage. Es stellt sich dann die Frage, ob es nicht sinnvoll ist, den Namensraum-URI des jeweiligen Dokumentationsformat für das Präfix doc: zu verwenden.

Das ist aus folgendem Grund nicht möglich: Wenn die Ausgabe, die das XSLT-Programm und die Ausgabe, die das Dokumentationsprogramm erzeugen sollen, beide aus dem selben Namensraum stammen, kann das Dokumentationsprogramm bei seiner Arbeit nicht erkennen, was zur Dokumentation und was zum Programm gehört. Da aber alle für die Dokumentation in Frage kommenden XML-Vokabulare aus offensichtlichen Gründen auch beliebte Ausgabeformate eines XSLT-Programm sind, muss ein generischer Ansatz diesen Sachverhalt berücksichtigen. Aus diesem Grund muss sich die Dokumentation in einem eigenen Namensraum befinden.

xsltdoc — Implementierung des Dokumentationsprogramms

Wie sind nun die vorausgehenden Erläuterungen in der Software implementiert? Welche Eigenschaften der Software sind wünschenswert, welche optional?

xsltdoc zeichnet sich durch folgende Eigenschaften aus:

  1. Es gibt keine Festlegung auf ein Dokumentationsformat (XHTML, Docbook usw.).

  2. Bei der Dokumentation besteht nicht die Notwendigkeit, den Dokumentationsnamensraum als Erweiterungsnamensraum zu deklarieren und mit xslt:fallback zu arbeiten. Dies ist nur dann erforderlich, wenn Dokumentation innerhalb von Templates geschrieben werden soll.

  3. Das dokumentierte XSLT-Programm kann unmittelbar durch eine XSLT-Engine ausgeführt werden. Es ist kein Preprocessing notwendig, um das Programm aus der dokumentierten Datei zu extrahieren. Dies ist der wesentliche Unterschied zu klassischen Literate-Programming-Ansätzen, bei denen in je einem Preprocessing-Schritt Dokumentation sowie lauf- und compile-fähiger Code erzeugt wird.

  4. Falls Dokumentation in einem Template gewünscht ist und die Arbeit mit xslt:fallback vermieden werden soll, kann xsltdoc den genannten Preprocessing-Schritt durchführen.

Zusammengefasst implementiert xsltdoc alle diskutierten Ansätze und erlaubt dem Programmierer frei aus den Möglichkeiten zu wählen. Die Tabelle stellt die Möglichkeiten in einer Übersicht dar und zeigt in welchen Fällen das dokumentierte XSLT-Programm direkt lauffähig ist und wann ein Preprocessing durch xsltdoc erforderlich ist.

EntscheidungsmatrixErweiterungsnamensraum und xslt:fallbacks
janein
Dokumentation innerhalb von TemplatesjaXSLT-Programm ist direkt lauffähigPreprocessing durch xsltdoc notwendig
neinXSLT-Programm ist direkt lauffähig
(Erweiterungsnamensraum und xslt:fallbacks sind nicht erforderlich, wenngleich zulässig)
XSLT-Programm ist direkt lauffähig

Es bleibt noch die Frage wie xsltdoc unabhängig vom Dokumentationsformat sein kann. Soweit es die doc:-Elemente betrifft ist die Angelegenheit einfach: xsltdoc kopiert die Elemente auf die Ausgabe. Für die xslt:-Elemente ist allerdings eine Umwandlung in das Zielformat zu leisten. Dazu greift xsltdoc auf ein externes Transformationsprogramm zurück. Dieser Teilprozess ist also nicht wirklich unabhängig vom Dokumentationsformat; eine teilweise Unabhängigkeit wurde nur durch Auslagerung des Problems erreicht. Die hier zur Verfügung stehende Referenzimplementierung greift auf xml2html zurück, um die xslt:-Elemente nach XHTML zu transformieren. In diesem Fall muss die Dokumentation auf XHTML basieren. xsltdoc besteht daher aus zwei Teilen:

  1. Die Kernsoftware: xsltdoc.xslt

  2. Ein Teil der abhängig vom Ausgabeformat ist. Bislang ist ausschließlich die Unterstützung für XHTML implementiert: xsltdoc-html.xslt.

Benutzung von xsltdoc — Anleitung für XSLT-Programmierer

Wenn Sie Ihre XSLT-Programme mit xsltdoc dokumentieren und die Dokumentation in XHTML ausgeben möchten, gehen Sie bitte wie folgt vor. Auf der linken Seite der folgenden Tabelle sehen Sie die Beschreibung der einzelnen Schritte; rechts finden Sie die Schritte für ein Beispiel.

SchrittBeschreibungBeispiel
1

Ergänzen Sie die xsltdoc-Namensräume in Ihrem XSLT-Programm.

xmlns:doc="http://www.linkwerk.com/namespaces/2005-02-03/xsltdoc/output/"
xmlns:xsltdoc="http://www.linkwerk.com/namespaces/2005-02-03/xsltdoc/"

Statt doc und xsltdoc können Sie belibiege andere Präfixe verwenden.

2

Schreiben Sie die Programmdokumentation unter Verwendung von XHTML-Elementen. Leiten Sie diese Elemente mit dem Präfix doc: ein. Plazieren Sie Dokumentation zunächst nur außerhalb von Templates.

<doc:p>erläuternder Text für ein Template</doc:p>
3

Optional: Ergänzen Sie bei Bedarf xsltdoc-Elemente, um die Ausgabe zu verfeinern. Eine Beschreibung der xsltdoc-Elemente finden Sie weiter unten.

Beispiel eines dokumentierten XSLT-Programms, das alle Features benutzt: listing3.xslt

4

Formatieren Sie Ihr dokumentiertes XSLT-Programm mit xsltdoc-html.xslt (XHTML-Ausgabe).

xsltengine -in listing3.xslt -xslt xsltdoc-html.xslt -out listing3.html-param comments drop

Die konkrete Aufrufsyntax hängt von der verwendeten XSLT-Engine ab.

Der Parameter comments=drop sorgt dafür, dass Kommentare aus dem XSLT-Programm nicht dargestellt werden. Dies ist eine Funktion des zugrundeliegenden xml2html.

5

Betrachten Sie das formatierte und dokumentierte XSLT-Programm.

listing3.html

Software und Referenzdokumentation

Download der Software

Open Source logo

Aufrufsyntax für XHTML-Dokumentation

xsltengine -in yourStylesheet.xslt -xslt xsltdoc-html.xslt -out out.html [-param name value]

Parameter von xsltdoc

xsltdoc kennt folgende Parameter:

xsltdoc-mode = [gendoc|stripdoc]

Mit dem Wert gendoc erzeugt xsltdoc die Dokumentation. Mit dem Wert stripdoc entfernt xsltdoc aus den Eingabedaten alle Dokumentationselemente und liefert nur das unkommentierte XSLT-Programm als Ausgabe. Das ist geeignet, um xsltdoc das oben genannte Preprocessing durchführen zu lassen.

Namensraumdeklarationen für xsltdoc

xsltdoc verwendet zwei Namensräume: einen für die eingebettete Dokumentation und einen für die nachfolgend beschriebenen Elemente und Attribute, die bei der Formatierung berücksichtigt werden.

Die übliche Deklaration der Namensräume sieht wie folgt aus (die Präfixe sind selbstverständlich frei wählbar):

xmlns:doc="http://www.linkwerk.com/namespaces/2005-02-03/xsltdoc/output/"
xmlns:xsltdoc="http://www.linkwerk.com/namespaces/2005-02-03/xsltdoc/"

Elemente und Attribute

<xsltdoc:containerstart xsltdoc:type="X">

Generiert in der Dokumentation einen Start-Tag vom Typ X. Dies ist nützlich, um die Dokumentation in Abschnitte zu gliedern. Es ist in XSLT nicht möglich unterhalb des Wurzelelements fremde Containerelemente für Templates anzulegen. Aus diesem Grund ist es erforderlich, Start- und End-Tags solcher Container zu Dokumentationszwecken separat zu ergänzen. Diese Aufgabe erfüllt (für ein Start-Tag) dieses xsltdoc-Element. Wichtig: Es liegt in der Verantwortung des XSLT-Programmierers dafür zu sorgen, dass auf diesem Wege erzeugte Start- und End-Tags zu einer wohlgeformten XML-Ausgabe führen.

<xsltdoc:attribute xsltdoc:name="X" xsltdoc:value="Y"/>

Elemente dieses Typs stehen im Inhalt eines xsltdoc:containerstart-Elements und ergänzen das dort erzeugte Start-Tag um ein Attribut der Form X="Y".

<xsltdoc:containerend xsltdoc:type="X"/>

Generiert in der Dokumentation einen End-Tag vom Typ X.

<xsltdoc:displaySource xsltdoc:idref="X"/>

Dieses leere Element, das innerhalb der Dokumentation stehen soll, erzeugt die Ausgabe des Programmteils dessen xsltdoc:id den Wert X besitzt.

xsltdoc:id (Attribut)

Ein Attribut dieses Typs dient dazu Teile des XSLT-Programms (z.B. ein Template) mit einer eindeutigen xsltdoc:id zu kennzeichnen.

Erweiterung für weitere Ausgabeformate

Falls Sie xsltdoc für ein neues Ausgabeformat erweitern möchten, so verwenden Sie am besten xsltdoc-html.xslt und xml2html.xslt als Vorlage. In xsltdoc.xslt gibt es ein Template für /, den Wurzelknoten des XPath-Datenmodells. Dort beginnt die Verarbeitung. xsltdoc.xslt ruft dann das benannte Template mit dem Namen xsltdoc-start auf. Dies ist in xsltdoc-html.xslt enthalten und erzeugt den XHTML-Rahmen. Ab dort findet im wesentlichen eine Verarbeitung gemäß der normalen Verarbeitungsreihenfolge mittels apply-templates statt. Alle Elemente aus dem doc- und dem xsltdoc-Namensraum verarbeitet xsltdoc.xslt. Alle anderen, also alle beliebigen XML-Elemente transformiert xml2html.xslt nach XHTML.

Auf Wunsch veröffentliche ich Ihre Erweiterungen für neue Ausgabeformate gerne an dieser Stelle; oder ich verlinke Ihre Seiten. Auf meiner Wunschliste stehen FO, Docbook und WordML. Derzeit habe ich keine Pläne, ob/wann ich dies selbst implementieren kann. Um doppelte Arbeit zu vermeiden, schicken Sie mir doch eine Mail, wenn Sie mit der Implementierung beginnen.

Stefan Mintert, $Date: 2005/02/03 17:08:00 $

Valid XHTML 1.0!