... [Seminar XML und Java] ... [Thema: XSLT] ... [Anwenden von Templates] ...
Man muss die zwei Begriffe Template und Template Rule unterscheiden. Eine Template Rule definiert Regeln für den Transformationsprozess und enthält immer ein Template. Das Template ist ein Stück Stylesheet, das im Ergebnisdokument instanziiert wird. Im folgenden Beispiel ist das gesamte Konstrukt eine Template Rule, der hervorgehoben dargestellte Teil ist das Template.
<xsl:template match="ims-object">;
<h1><xsl:apply-templates select="eb_nummer /></h1>;
<h2><xsl:apply-templates select="bezeichnung /></h2>;
<div class="beschreibung"><xsl:apply-templates select="text /></div>;
</xsl:template>
Template Rules werden mit dem Element xsl:template
definiert:
<!-- Category: top-level-element -->
<xsl:template
match = pattern
name = qname
priority = number
mode = qname>
<!-- Content: (xsl:param*, template) -->
</xsl:template>
xsl:apply-templates
oder xsl:for-each
explizit gesteuert werden.
Beispiel:
<xsl:template match="SPIELORT" >
[...]
</xsl:template>
Diese Template Rule passt auf ein Element "SPIELORT" im Quelldokument.
Ein Pattern beschreibt eine Regel, nach der eine Template Rule für einen Knoten ausgewählt wird. Ein Knoten passt ("match") dann zu einem Pattern, wenn er zu dem Node Set gehört, das sich durch die Anwendung des Pattern mit dem zu testenden Knoten selbst oder einem seiner Vorfahren als Context Node ergibt.
Das Matchen könnte also z.B. folgendermaßen ablaufen: der zu prüfende Knoten wird als Context Node gesetzt und der Pattern in diesem Kontext ausgewertet. Ist der zu testende Knoten nicht im resultierenden Node Set enthalten, wird als nächster Context Node der Elternknoten des zu testenden Knotens benutzt. Dieser Vorgang wiederholt sich so lange, bis kein Vorfahre mehr übrig ist oder der zu testende Knoten im Node Set erscheint. Im ersten Fall passt der Knoten eben nicht auf den Pattern.
Beispiele:
/ | Wurzelelement |
* | jedes Element |
@* | jedes Attribut |
absatz | jedes Element absatz |
absatz | einschub | jedes Element absatz oder einschub |
kuenstler/name | jedes Element name als Kind von kuenstler |
buch//absatz | jedes Element absatz unterhalb von buch |
text() | Textelemente |
absatz[1] | jedes Element absatz, das das erste Kind seines übergeordneten Elements ist |
*[position()=1 and self::absatz] | dito |
list-el[position() mod 2 = 1] | trifft jedes ungerade Element list-el |
kapitel[@class="anhang"]//absatz | jedes Element absatz mit einem Vorfahren kapitel, dessen Attributwert für class 'anhang' ist. |
Über das mode
-Attribut kann ein Element des Quelldokuments auf unterschiedliche Weise transformiert werden. Das ermöglicht die Definition unterschiedlicher Template Rules für ein und dasselbe Pattern. Wird beim Ausführen von Templates kein mode
spezifiziert, wird eine Template Rule ohne mode
-Attribut gesucht und ausgeführt.
Beispiel:
<xsl:template match="images" mode="einfach" >
<!-- Transformiere ein images-Element in einfacher Form -->
</xsl:template>
<xsl:template match="images" mode="genaue" >
<!-- Transformiere ein images-Element in genauer Form -->
</xsl:template>
name
benennt die Template Rule. Mittels xsl:call-template
kann eine Template Rule dann explizit zur Ausführung gebracht werden. So können Template Rules definiert werden, die unabhängig vom Knoten des Quelldokuments Sinn machen. Dies könnte eine Art "Baustein" sein, der unabhängig vom aktuellen Kontext beliebig häufig benutzt werden kann.
Beispiel:
<xsl:template name="tabellenkopf">
<!-- Baustein für einen Tabellenkopf -->
</xsl:template>
Manchmal kommt es vor, dass es für einen zu testenden Knoten mehr als eine passende Template Rule gibt. Möglich wäre dies zum Beispiel durch den Import von Stylesheets oder auch einfach durch unterschiedliche Template Rules, die durch ihr Pattern für einen und denselben Knoten in Frage kommen.
Die Auflösung solcher Konflikte läuft in drei Schritten ab. Zuerst einmal wird eine Liste aller in Frage kommenden Template Rules gebildet. Von diesen werden dann nur die weiter betrachtet, die die höchste Importpräzedenz haben.
Diese werden anschließend nach Ihrer Priorität bewertet. Die Priorität wird über das entsprechende Attribut der Template Rules gesteuert. Gibt es hier immer noch Alternativen, wird dies als Fehler behandelt.
Fehlt allerdings das entsprechende Attribut, wird eine Standardpriorität aus dem Pattern der Template Rule berechnet. Diese ergibt sich wie folgt:
processing-instruction()
nach einem child::
- oder attribute::
-Axis Specifier besteht, z.B. absatz, @href
oder child::processing-instruction(presentation-manager)
.
NCName:*
nach einem child::
- oder attribute::
-Axis Specifier besteht, z.B. child::ims:*
.
text(), comment(), node()
) nach einem child::
- oder attribute::-
Axis Specifier besteht, z.B. child::text()
.
Mit diesen Regeln wird die Wichtigkeit der Template Rules nach ihrer Spezialisierung gestaffelt. Der am häufigsten auftretende Fall, der Test auf einen bestimmten Namen, wird mit der Priorität 0 bewertet. Weniger spezifische Patterns erhalten eine kleinere Priorität. Was dann übrig bleibt, ist auf jeden Fall spezieller als der allgemeine Fall.
Beispiel:
<xsl:template match="text">
<!-- Tu was mit text -->
</xsl:template>
<xsl:template match="image/text">
<!-- Tu was anderes mit text -->
</xsl:template>
Wird jetzt irgendwo <xsl:apply-templates select="text" />
aufgerufen, sind in dem Fall, dass das Element text
unterhalb eines image
-Elements steht, beide Templates Kandidaten für die Ausführung. Jetzt greift die Priorisierung: Das erste Template hat die Priorität 0, das zweite bekommt, da es einen spezielleren Fall behandelt, die Priorität 0,5 und wird somit instanziiert.
Literal Result Elements sind all die Elemente, die nicht zum Namensraum von XSLT und nicht zu den Extension Namespaces gehören. Für ein Literal Result Element wird im Ergebnisdokument ein Element erzeugt, das den gleichen Expanded Name wie im Stylesheet erhält. Außerdem bekommt es eine Kopie aller Attribute, die es im Stylesheet besitzt. Auch die Namespace Nodes des Elements werden kopiert, wenn:
extension-element-prefixes
-Liste gehört
exclude-result-prefixes
-Liste gehört.
Beispiel:
<xsl:template match="ims-object">
<html>
<head>
<title><xsl:apply-templates select="eb_nummer"/></title>
</head>
<body>
<h1>Objekt: <xsl:apply-templates select="bezeichnung"/></h1>
</body>
</html>
</xsl:template>
Die hervorgehobenen Elemente sind Literal Result Elements. Das Ergebnis könnte dann so aussehen, wobei der Wert für eb_nummer
mit 1999/05/0001, der Wert des Elements bezeichnung
mit Kartenspiel angenommen wird:
<html>
<head>
<title>1999/05/0001</title>
</head>
<body>
<h1>Objekt: Kartenspiel</h1>
</body>
</html>
Templates können mit Parametern versehen werden. Diese können mit Vorgabewerten (select="left"
im Beispiel) versehen werden, die dann zum Einsatz kommen, wenn ein Parameter nicht spezifiziert wurde. Zum Einsatz kommt hier das xsl:param
-Konstrukt, das später noch genauer erklärt wird.
Beispiel:
<xsl:template match="image">
<xsl:param name="align" select="left"/>
<img src="org" align="{$align}"/>
</xsl:template>
... [Seminar XML und Java] ... [Thema: XSLT] ... [Template Rules] ... [Anwenden von Templates] ...