Mehrere Ergebnisdokumente

(Auszug aus "XSLT 2.0 & XPath 2.0" von Frank Bongers, Kapitel 3.)

Soll aus einem oder mehreren XML-Dokumenten eine Vielzahl von Ergebnis­dokumenten im Verlauf einer einzigen Transformation erzeugt werden – dies ist beispielsweise erforderlich, wenn auf diesem Wege eine komplette Website statisch erzeugt werden soll –, musste bisher auf Erweiterungs­instruktionen wie saxon:output, xt:document, exsl:document oder ähnliche zurückge­griffen werden. XSLT 2.0 führt mit vergleichbarer Funktionalität die neue Instruktion xsl:result-document ein.

XSLT 2.0 unterscheidet dabei zwischen einer primären Ergebnissequenz, dem »eigentlichen« Ergebnis der Transformation, und einer beliebigen Anzahl sekundärer Ergebnissequenzen, die jeweils durch eine xsl:result-doku­ment-Instruktion erzeugt werden. Hierbei kann zum einen pro erzeugtem Dokumentknoten ein URI angegeben (Dateiname des zu erzeugenden Doku­ments und der Pfad zu seinem Speicherort), zum anderen über das name-Attri­but eine eigene benannte Ausgabeformatdefinition xsl:output herangezogen.

Erzeugung eines HTML-Framesets mit xsl:result-document

Szenario ist ein umfangreicheres XML-Dokument (in der Praxis kann es belie­big viel umfangreicher sein als in diesem Beispiel ausgeführt), dessen Inhalt auf mehrere HTML-Dokumente verteilt in einem Frameset dargestellt werden soll.

Das Stylesheet hat in diesem Fall drei parallel zu erfüllende Aufgaben:

  • Erzeugung des Framesetdokuments
    Das Framesetdokument wird in Form des primären Ergebnisdokuments realisiert. Es sit daher nötig, die unbenannte xsl:output-Deklaration entsprechend auf ein XHTML-Frameset-Dokument abzustimmen.
  • Erzeugung der Framesetnavigation
    Das Navigationsdokument wird als sekundäres Ergebnisdokument mit xsl:result-document in einem benannten Template erzeugt, das genau einmal aufgerufen wird. Hierbei fin­den auch Templatemodi Verwendung. Die xsl:result-document-Instruktion muss sich, wie auch bei der Erzeugung der Inhaltsseiten, auf eine benannte Outot-Deklaration beziehen.
  • Erzeugung der Inhaltsseiten

Die Inhaltsseiten werden ebenfalls mit xsl:result-document erzeugt. Die Dateinamen ergeben sich dabei aus der Position der auszugebenden Inhalte im Quelldokument und werden mittels AVT erzeugt.

Der erzeugte Frameset im Bowser (frameset-artikel.html)

Abbildung: Der erzeugte Frameset im Bowser (frameset-artikel.html).

Das Quelldokument

Die Struktur des Quelldokuments ist folgende:

<?xml version="1.0" encoding="ISO-8859-1" ?> 
<artikel>
  <kapitel>
    <titel>XML-Grundlagen</titel> 
    <abschnitt>
      <ueberschrift>...</ueberschrift> 
      <absatz>...</absatz> 
      <absatz>...</absatz> 
    </abschnitt>
    <!-- mehr Abschnitte -->
  </kapitel>
  <!-- mehr Kapitel -->
</artikel>

Code-Beispiel: kap03/3.09/artikel.xml (Ausschnitt).

Der Artikel besteht aus einer Folge von Kapiteln, die wiederum in Abschnitte mit je einer Überschrift untergliedert sind. Im Frameset soll für jeden Abschnitt eine separate Inhaltsseite generiert werden.

Das Framesetdokument

Die Erzeugung des Framesetdokuments ist noch simpel; es handelt sich ja nur um die Ausgabe von Literal Result Elements. Hierfür wird das Template mit match auf den Dokumentknoten eingesetzt:

<xsl:template match="/">
  <!-- Frameset schreiben: -->
  <html>
    <head><title>Artikel über XML</title></head>
    <frameset cols="200,*">
      <frame name="navigation" src="navigation.html" />
      <frame name="inhalt" src="kapitel1.html" />
    </frameset>
  </html>
  <!-- Navigation erzeugen -->
  <xsl:call-template name="navigation"/>
  <!-- Inhalte verarbeiten -->
  <xsl:apply-templates select="abschnitt"/>
</xsl:template>

Code-Beispiel: kap03/3.09/frameset_erzeugen.xsl (Ausschnitt).

Hier werden die Struktur des Framesets, die Bezeichner der Frames und ihre Startkonfiguration festgelegt. Die hier genannten Dateien müssen ebenfalls im Zuge dieser Transformation erzeugt werden.

Die unbenannte Output-Deklaration, auf die sich das primäre Ergebnisdokument stets bezieht, muss für ein XHTML-Frameset-Dokument wie folgt lauten:

<xsl:output method="xhtml" encoding="ISO-8859-1" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0 Frameset//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"/>

Code-Beispiel: kap03/3.09/frameset_erzeugen.xsl (Ausschnitt).

Zu beachten sind die beiden Instruktionen, die der Ausgabe des Framesets fol­gen. Ohne sie würde keine weitere Verarbeitung stattfinden.

Das Navigationsdokument

Die Erzeugung der Navigation wird mittels eines benannten Templates ange­stoßen. Dies ist in diesem Falle günstiger, als über xsl:apply-templates die Inhalte aufzurufen und dann zu entscheiden. Das Hinzufügen der Inhalte zur Navigation geschieht mittels Template-Modes, da für Teile der Inhalte auch Regeln im Default-Mode existieren:

<xsl:template name="navigation">
  <!-- Navigation schreiben: -->
  <xsl:result-document href="navigation.html" format="inhalt">
    <html>
      <body bgcolor="#DDDDDD">
        <xsl:apply-templates mode="navigation"/>
      </body>
    </html>
  </xsl:result-document>
</xsl:template>

Code-Beispiel: kap03/3.09/frameset_erzeugen.xsl (Ausschnitt).

Zu beachten ist zunächst die Instruktion xsl:result-document. Sie erzeugt einen Dokumentknoten, an den die hier erzeugten Inhalte angehängt werden, die somit nicht Teil der primären Ergebnissequenz werden. Im href-Attribut der Instruktion wird der Dateiname übergeben, unter dem das Dokument serialisiert werden soll. Er wird als relativer URI-String angesehen, der sich auf den Basis-URI des Stylesheets bezieht. In diesem Beispiel wird nur ein Dateiname genannt, das in diesem Template erzeugte Dokument naviga­tion.html also im gleichen Ordner wie das Framesetdokument gespeichert. Dies entspricht auch dem Ordner, in dem sich das Stylesheet befindet.

In das Navigationsdokument sollen noch weitere Inhalte eingefügt werden, nämlich die Kapitelüberschriften zur Orientierung und die Abschnitts­­überschriften, die als Link zu den Inhalten dienen sollen. Da beide Elemente ebenfalls im Inhalt verarbeitet werden, jedoch auf abweichende Art, werden für die Navigation eigene Templateregeln entworfen, die durch den Mode "navigation" gekennzeichnet sind:

<xsl:template match="titel" mode="navigation">
  <p><b><xsl:value-of select="."/>:</b></p>
</xsl:template>

Code-Beispiel: kap03/3.09/frameset_erzeugen.xsl (Ausschnitt).

Die Titel der Kapitel werden ganz simpel ausgelesen und als HTML-Absatz dar­gestellt. Zu beachten ist, dass kein Template für das Elternelement <kapitel> existiert, weder mit noch ohne mode-Angabe! Dies bedeutet, dass das Default-Template für Elementknoten aufgerufen wird. Das macht weiter nichts aus, da hier der aktuelle Template-Mode transparent weitergegeben wird; die aus dem Default-Template erfolgenden weiterführenden Aufrufe erfolgen alle ebenfalls mit mode="navigation" (ansonsten wäre die Kette unterbrochen).

Interessanter ist das Template für die Abschnitte:

<xsl:template match="abschnitt" mode="navigation">
  <p><a target="inhalt" href="kapitel{count(preceding::abschnitt)+1}.html"><xsl:value-of select="ueberschrift"/></a></p>
</xsl:template>

Code-Beispiel: kap03/3.09/frameset_erzeugen.xsl (Ausschnitt).

Dieses Template holt sich die Überschrift des jeweilig verarbeiteten Abschnitts und bildet aus ihr den Link zum Frameinhalt. Aus diesem Grunde muss der Link ein target-Attribut erhalten, dessen Wert dem im Framebezeichner ent­spricht. Für den Link muss ein Dateiname generiert werden (der dem des kor­respondierenden Inhaltsdokuments entsprechen muss). Dieser Name soll einer einfachen Konvention entsprechen – der String "kapitel" gefolgt von der Position des Abschnitts im Dokument.

Die sichere Methode, diese Information zu erhalten, ist über das Zählen der Vorgängerelemente gleichen Namens; die Funktion position() versagt hier, da keine explizite Nodesequenz aus <abschnitt>-Elementen gebildet wurde (ansonsten wäre dies eine Alternative). Es muss zum ermittelten Wert 1 dazu­gezählt werden, um die tatsächliche Position zu erhalten.

Die Inhaltsdokumente

Die Darstellung der Inhaltsdokumente erfolgt analog zu der des Navigations­­dokuments, es wird hierfür allerdings die Nodesequenz verwendet, die der Aufruf von xsl:apply-templates aus dem primären Template erzeugt. Es wird dabei eine Node-Sequenz aus Elementen <abschnitt> erzeugt. Ein Template-Mode wird hier nicht eingesetzt:

<xsl:template match="abschnitt">
  <xsl:result-document format="inhalt" href="kapitel{count(preceding::abschnitt)+1}.html">
    <html>
      <body bgcolor="#EEEEEE">
        <h1>Kapitel: <xsl:value-of select="preceding-sibling::titel"/></h1>
        <!-- Inhalte verarbeiten -->
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:result-document>
</xsl:template>

Code-Beispiel: kap03/3.09/frameset_erzeugen.xsl (Ausschnitt).

Steht beim Navigationsdokument der zu erzeugende Dateiname noch fest – es wird ja nur ein einziges derartiges Dokument benötigt –, so besteht hier die Notwendigkeit, eine ganze Reihe von Dokumenten mit unterschiedlichen Dateinamen zu generieren. Dies kann nach dem gleichen Prinzip geschehen, wie es für die Erzeugung der Links im Navigationsdokument erfolgte: Das href-Attribut von xsl:result-document erlaubt den Einsatz eines Attribut­wert-Templates. Die Formatierung der weiteren Inhalte geschieht mit folgen­den beiden Regeln:

<xsl:template match="ueberschrift">
  <h3><xsl:apply-templates/></h3>
</xsl:template>
<xsl:template match="absatz">
  <p><xsl:apply-templates/></p>
</xsl:template>

Code-Beispiel: kap03/3.09/frameset_erzeugen.xsl (Ausschnitt).

Die Output-Deklaration zu xsl:result-document

Ein wenig versteckt wurde oben ein weiteres Attribut von xsl:result-document präsentiert: das format-Attribut. Es ist optional und bezieht sich auf eine mittels xsl:output erzeugte Output-Format-Deklaration.

<xsl:result-document format="inhalt" ...>
  ...
</xsl:result-document>

Im Gegensatz zu den im ersten Kapitel vorgestellten Output-Deklarationen gibt es einen entscheidenden Unterschied: Das format-Attribut bezieht sich auf eine benannte Output-Deklaration. Es muss also eine entsprechende Deklara­tion vorliegen, die über ein name-Attribut (Anmerkung: Das name-Attribut von xsl:output steht, genau wie die Instruktion xsl:result-document, die dieses referenziert, in XSLT 1.0 noch nicht zur Verfügung.) mit dem genannten Bezeichner ver­fügt:

<xsl:output name="inhalt" method="xhtml" encoding="ISO-8859-1" indent="no" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>

Code-Beispiel: kap03/3.09/frameset_erzeugen.xsl (Ausschnitt).

Diese Deklaration wird für das primäre Ergebnisdokument nicht berücksich­tigt; dieses bezieht sich stets auf die unbenannte Output-Deklaration. Das Gleiche gilt auch für xsl:result-document, solange das format-Attri­but nicht eingesetzt wird.

Zusammenfassung

Mit Hilfe der Instruktionen xsl:result-document können hier in einem ein­zigen Transformationsvorgang mehrere Ergebnisdokumente erzeugt werden – in diesem Falle sind es acht Dokumente (Frameset, Navigation und sechs Inhaltsseiten); bei entsprechender Ausgestaltung des Quelldokuments könnten es beliebig viele mehr sein.

   

<< zurück vor >>
Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © Galileo Press, Bonn 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT 2.0 & XPath 2.0 ― Das umfassende Handbuch" denselben Bestimmungen wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Galileo Press, Rheinwerkallee 4, 53227 Bonn