XSLT - Der Aufbau eines Stylesheets


... [Seminar XML und Java] ... [Thema: XSLT] ... [Erzeugen des Ergebnisdokuments] ...


Übersicht: XSLT - Aufbau eines Stylesheets


xsl:stylesheet

Nachdem wir uns in den vorherigen Abschnitten die zentralen Elemente des Stylesheets, die Templates und Template Rules, angeschaut haben, wollen wir uns nun mit den restlichen Elementen des Stylesheets beschäftigen. Das Dokumentelement eines Stylesheets wird wie folgt definiert:

<xsl:stylesheet
  id = id
  extension-element-prefixes = tokens
  exclude-result-prefixes = tokens
  version = number>
  <!-- Content: (xsl:import*, top-level-elements) -->
</xsl:stylesheet>

<xsl:transform
  id = id
  extension-element-prefixes = tokens
  exclude-result-prefixes = tokens
  version = number>
  <!-- Content: (xsl:import*, top-level-elements) -->
</xsl:transform>

Das Konstrukt xsl:transform ist ein Synonym für xsl:stylesheet, einen Unterschied gibt es lediglich in ihrer Bedeutung für Dritte. Wenn es sich beim Stylesheet um eine Transformationsvorschrift handelt, ist xsl:transform die richtige Wahl, will man mit dem Stylesheet Ausgabeformatierungen mittels XSL-FO vornehmen, sollte man xsl:stylesheet verwenden.

Das version-Attribut muss angegeben werden. Hier hat man sich Gedanken über die Zukunft gemacht: Trifft ein XSLT-Prozessor auf ein Stylesheet, das Elemente einer höheren Version enthält als er selbst unterstützt, aktiviert er das so genannte Forward Compatible Processing. Damit bleibt sichergestellt, dass Stylesheets auch von älteren Prozessoren noch verarbeitet werden können.

Das Attribut extension-element-prefixes enthält eine Liste von Präfixen, durch Whitespaces getrennt. Elemente im Stylesheet mit diesen Präfixen werden als Extension Elements behandelt und nicht durch den XSLT-Prozessor sondern durch einen nicht näher definierten Prozess behandelt.

Über exclude-result-prefixes kann man Namespace-Präfixe deklarieren, die beim Erzeugen des Ergebnisdokumentes unterdrückt werden sollen.

Mittels des Attributs id schließlich kann man das Stylesheet-Element innerhalb einer anderen Ressource eindeutig identifizieren.


xsl:import und xsl:include

<!-- Category: top-level-element -->
<xsl:include
  href = uri-reference />

<xsl:import
  href = uri-reference />

Stylesheets können modularisiert werden. Hierzu gibt es zwei Möglichkeiten, nämlich xsl:include und xsl:import. Beide Anweisungen arbeiten auf der Baumebene, wobei das über das href-Attribut zu referenzierende Stylesheet als xml-Dokument behandelt und eine entsprechende Baumrepräsentation erzeugt wird. Diese wird dann an der Stelle der xsl:import- oder xsl:include-Anweisung in das aktuelle Stylesheet eingefügt. Dabei muss darauf geachtet werden, dass sich Stylesheets weder direkt noch indirekt selbst importieren oder inkludieren.

Der Unterschied liegt jetzt in der Behandlung der Templates bei Konflikten. Während ein inkludiertes Stylesheet die Reihenfolge der Template-Auflösung nicht ändert, bekommen importierte Templates eine niedrigere Importpräzedenz als die Templates des importierenden Stylesheets.

Imports müssen immer vor allen anderen Top Level-Elementen des Stylesheets auftreten. Hat ein inkludiertes Stylesheet ebenfalls Importanweisungen, werden diese hinter die Importanweisungen des inkludierenden Stylesheets gehängt.

Zuerst werden also die Inkludierungen ausgeführt. Anschließend werden die Imports so abgearbeitet, dass eine Art Importbaum entsteht. Importiert Stylesheet A die Stylesheets B und C, B importiert D, und C importiert E, ergibt sich folgender Baum:

Der beispielhafte Importbaum

Beispiel: Importbaum

Die Präzedenz ergibt sich aus diesem Baum, indem man erst die Nachfolger eines Knotens betrachtet und dann die Knoten selbst (von links nach rechts). Damit ergibt sich folgende Präzedenzfolge: D, B, E, C, A, wobei D die niedrigste und A die höchste Präzedenz hat.

Die Importpräzedenz hat Einfluss auf die Auswahl von Templates in Konfliktsituationen. Denn aus der Liste der möglichen Alternativen werden nur die Templates mit der höchsten Importpräzedenz berücksichtigt.


xsl:strip-space und xsl:preserve-space

<!-- Category: top-level-element -->
<xsl:strip-space
  elements = tokens />

<!-- Category: top-level-element -->
<xsl:preserve-space
  elements = tokens />

Mit diesen beiden Konstrukten kann die Liste der Elemente im Quelldokument, die einem White Space Stripping unterworfen oder davon ausgenommen (preserve) werden sollen, modifiziert werden. Das Attribut elems enthält je eine Liste von Tokens, also Namen, die mit Whitespaces voneinander getrennt sind. Als Vorgabe sind alle Elemente des Quelldokuments vom Whitespace-Stripping ausgenommen.


xsl:output

<!-- Category: top-level-element -->
<xsl:output
  method = "xml" | "html" | "text" | qname-but-not-ncname
  version = nmtoken
  encoding = string
  omit-xml-declaration = "yes" | "no"
  standalone = "yes" | "no"
  doctype-public = string
  doctype-system = string
  cdata-section-elements = qnames
  indent = "yes" | "no"
  media-type = string />

Mit xsl:output kann man das Ausgabeverhalten des XSLT-Prozessors beeinflussen.

Die Art und Weise wird über method festgelegt. Erlaubt sind hier die Werte xml, html und text sowie eine mögliche Ausgabemethode, über die in der Spezifikation nichts gesagt wird und die dann woanders festgelegt sein muss.

Weitere Attribute:

Der XSLT-Prozessor kann die Ausgabemethode auch durch Betrachtung des Ergebnisdokuments automatisch bestimmen.


xsl:namespace-alias

<!-- Category: top-level-element -->
<xsl:namespace-alias
  stylesheet-prefix = prefix | "#default"
  result-prefix = prefix | "#default" />

Wenn man mit einem XSLT-Stylesheet ein anderes XSLT-Stylesheet erzeugen will, kann es ganz nützlich sein, ein Namespace-Präfix von Literal Result Elements (stylesheet-prefix) beim Instanziieren durch ein anderes Namespace-Präfix (result-prefix) zu ersetzen. Das ist möglich mit xsl:namespace-alias.


Benannte Attributbausteine

<!-- Category: top-level-element -->
<xsl:attribute-set
  name = qname
  use-attribute-sets = qnames>
  <!-- Content: xsl:attribute* -->
</xsl:attribute-set>

Mit diesem Konstrukt kann man Bausteine erzeugen, die dann durch xsl:element, xsl:copy oder xsl:attribute verwendet werden können. Man kann in einem Attributbaustein auch wieder bereits definierte Bausteine einbinden. Inhalt des Bausteins sind xsl:attribute-Konstrukte.


Literal Result Elements als Stylesheet

Man kann ein Literal Result Element, also ein Element, das nicht zum XSLT-Namensraum gehört, als Dokumentelement haben:

<html xsl:version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns="http://www.w3.org/TR/xhtml1/strict">
  <head>
    <title>Expense Report Summary</title>
  </head>
  <body>
    <p>Total Amount: <xsl:value-of select="expense-report/total"/></p>
  </body>
</html>

ist äquivalent zu

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/TR/xhtml1/strict">
<xsl:template match="/">
<html>
  <head>
    <title>Expense Report Summary</title>
  </head>
  <body>
    <p>Total Amount: <xsl:value-of select="expense-report/total"/></p>
  </body>
</html>
</xsl:template>
</xsl:stylesheet>

Man spricht hier von einer vereinfachten Syntax. Allerdings kann solch ein Stylesheet keinerlei Top Level-Elemente beinhalten, d.h. es können keine weiteren Template Rules definiert oder andere Stylesheets eingebunden werden. Diese Vorgehensweise eignet sich also nur für kleinere Stylesheets.


Einbetten von Stylesheets

Stylesheets können in XML-Dokumente eingebettet werden. Um das Stylesheet über die <?xml-stylesheet [...] ?>-Processing Instruction ansprechen zu können, erhält das Stylesheet auf dem xsl:stylesheet-Element eine ID.


Variablen, Parameter und Result Tree Fragments

Man kann in einem Stylesheet Werte an Variablen und an Parameter binden:

<!-- Category: top-level-element -->
<!-- Category: instruction -->
<xsl:variable
  name = qname
  select = expression>
  <!-- Content: template -->
</xsl:variable>

<!-- Category: top-level-element -->
<xsl:param
  name = qname
  select = expression>
  <!-- Content: template -->
</xsl:param>

An jeder Stelle des Stylesheets können Werte an Variablen gebunden werden. Parameterbindungen sind dagegen nur innerhalb von Template Rules erlaubt, um diesen mitzuteilen, welche Parameter von außen an sie übergeben werden können und welche Vorgabewerte eventuell zu benutzen sind. Verwenden kann man sowohl Variablen als auch Parameter irgendwo innerhalb von XPath-Ausdrücken, wobei man über $qname auf den Wert zugreifen kann.

Die Sichtbarkeit bestimmt sich nach der Position im Stylesheet. Generell gilt, dass eine Variable nur für nachfolgende Knoten sichtbar ist. Das gilt auch für Template Rules, die während des Traversierens des Teilbaumes aufgerufen werden. War bereits eine Variable mit dem angegebenen Namen gebunden, überdeckt die neue Bindung die alte.

Um den Wert einer Variable oder eines Parameters zu bestimmen, darf nur eine der beiden Möglichkeiten, der select-Ausdruck oder das Template, verwendet werden. Wird beides nicht benutzt, wird ein leerer String an die Variable gebunden.

Der select-Ausdruck liefert als Ergebnis entweder einen String, eine Zahl, einen boolschen Wert oder ein Node Set. Darüber hinaus können durch eine erweiterte Funktionsbibliothek weitere Ergebnistypen eingeführt werden. Einer dieser Typen wird von XSLT selbst eingeführt, das Result Tree Fragment. Wird als Inhalt von xsl:variable oder xsl:param ein Template angegeben, wird dieses instanziiert. Diese Instanz wird in ein Dokumentfragment unterhalb eines neu erzeugten, frei stehenden Root Nodes gespeichert. Der Unterschied zu einem Node Set liegt darin, dass auf einem Node Set alle Operationen erlaubt sind, auf einem Result Tree Fragment nur solche, die auch auf einem Stringwert erlaubt sind.


... [Seminar XML und Java] ... [Thema: XSLT] ... [Aufbau eines Stylesheets] ... [Erzeugen des Ergebnisdokuments]