xsl:variable

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

A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

 

Mit der Anweisung xsl:variable wird eine benannte Variable definiert, deren Wert für die Dauer ihrer Gültigkeit jedoch nicht verändert werden kann. Eine Variable kann global für das gesamte Stylesheet oder lokal in einer Template-Regel deklariert werden.

Klassifizierung Deklaration/Instruktion
Funktionsgruppe Variablendefinition
Einführung XSLT 1.0

Position im Stylesheet und erlaubte Inhalte:

xsl:variable tritt sowohl als Toplevel-Element als auch als Instruktion auf. Wird es als Toplevel-Element, also als Kindelement von xsl:stylesheet oder xsl:transform eingesetzt, so erzeugt es eine globale Variable. Wird es hingegen innerhalb einer Template-Regel xsl:template als Instruktion verwendet, erzeugt es eine für diese Template-Regel gültige lokale Variable.

Das Element muss leer sein, wenn ihr select-Attribut eingesetzt wird. Besitzt sie kein select-Attribut, so muss sie einen Templatebody in Form eines Sequenzkonstruktors enthalten, der aus XSLT-Instruktionen, Text und literalen Ergebniselementen in beliebiger Zusammensetzung bestehen kann. Der Sequenzkonstruktor erzeugt in diesem Fall einen temporären Baum, auf den bei Referenzierung der Variable zugegriffen werden kann.

Attribute:

Für xsl:variable gelten die Standardattribute. Gültig sind des weiteren ein obligatorisches name-Attribut und ein optionales select-Attribut. Ab XSLT 2.0 kommt das Attribut as hinzu, das den geforderten Datentyp des Variablenwertes bezeichnet.

as

Wert

sequence-type

Verwendung

optional

Einführung

XSLT 2.0

Das as-Attribut legt den Datentyp des Variablenwertes fest. Der Attributwert muss einen Sequence-Type nach XPath 2.0 bezeichnen – wird das as-Attribut eingesetzt, so muss der Wert der Variable dem vorgegebenen Typ entsprechen.

Ist dies nicht der Fall, so wird keine Typkonvertierung versucht. Ein Fehlschlagen der Konvertierung wird entsprechend als Typfehler gewertet (ERR XTTE0590). Ist kein as-Attribut vorhanden, so wird der Wert der Variable entsprechend dem ausgewerteten select-Ausdruck bzw. dem enthaltenen Sequenzkonstruktor unverändert übernommen.

Hinweis: Das Attribut existiert nicht in XSLT 1.0.

name

Wert

qname

Verwendung

obligatorisch

Einführung

XSLT 1.0

Das obligatorische name-Attribut bestimmt den Namen der Variablen, mit dem diese im Stylesheet referenziert wird. Es handelt sich um einen QName. Es dürfen niemals mehrere namengleiche Variablen derselben Importpräzedenz oder desselben Gültigkeitsbereichs (Scope) auftreten – d.h. keine namensgleichen globalen Variablen oder namensgleichen lokalen Variablen innerhalb ein und derselben Template-Regel. Ist das der Fall, so wird ein statischer Fehler gemeldet (ERR XTSE0580).

Namensgleichheit ist gestattet für folgende Fälle:
Zwei oder mehr gleich benannte globale Variablen besitzen unterschiedliche Importpräzedenz. Treten Namensdopplungen durch Import eines externen Stylesheetmoduls auf, so gilt der Wert der Variablen mit der höchsten Importpräzedenz, normalerweise also der des Hauptmoduls. Der Wert der Variablen mit der geringeren Präzedenz ist nicht zugänglich.

Eine Namensgleichheit zwischen einer globalen und einer lokalen Variable ist unproblematisch. Die lokale Variable überschattet (shadows) innerhalb der Template-Regel, für die sie definiert ist gegebenenfalls die gleichnamige globalen. Der Wert der globalen Variable ist daher innerhalb dieser Template-Regel nicht zugänglich.

Eine Namensgleichheit lokaler Variablen, die in verschiedenen Template-Regeln deklariert sind, ist unproblematisch, da sich ihre Gültigkeitsbereiche nicht überschneiden. Jede lokale Variable gilt nur während der Laufzeit ihrer Template-Regel und ist außerhalb dieser daher nicht zugänglich bzw. nicht existent.

select

Wert

xpath-expression

Verwendung

optional

Einführung

XSLT 1.0

Das select-Attribut dient alternativ zu einem möglichen Sequenzkonstruktor im Inneren von xsl:variable zur Erzeugung des Wertes der Variable. Das Attribut enthält einen XPath-Ausdruck, dessen Auswertung den gewünschten Wert ergibt. Ist das select-Attribut gesetzt, so muss das Element leer sein (die Spezifikation sieht jedoch nicht explizit eine Fehlermeldung vor).

Ergebnis der Auswertung ist eine Sequenz. Zahlen können unmittelbar als Literale übergeben werden, Strings müssen in diesem Fall – zusätzlich zu den Attributwertbegrenzern! – in Anführungszeichen eingeschlos­sen sein:

<xsl:variable name=stringvariable select="'mein stringwert'"/>

Verwendungszweck:

Eine Variable ist in XSLT genau wie in anderen Pro­grammiersprachen ein benannter Speicher für Werte. Der wesentliche Unter­schied von XSLT-»Variablen« besteht darin, dass deren Wert nach einmaliger Zuweisung, die bei der Deklaration der Variable (nicht später) geschehen muss, nicht wieder geändert werden kann.

Es können daher nicht beliebig Werte in Variablen abgelegt (Anmerkung: Es gibt prozessorspezifische Erweiterungen, beispielsweise für Saxon, die nachträgliche Neuzuweisung zur Laufzeit ermöglichen, mit saxon:assign für durch saxon:assig-nable="yes" markierte Variablen). Für den XSLT-Standard ist dies jedoch auch für die Zukunft nicht geplant, da auf diesem Wege die Freiheit von Seiteneffekten bei der XSLT-Verarbeitung unterlaufen wird.) oder aufsum­miert werden. Bereits ein einfacher Zähler vergleichbar mit i++ ist in XSLT nicht ohne weiteres zu realisieren, sondern nur auf Umwegen mit rekursiven Templateaufrufen.

Eine XSLT-Variable ähnelt in ihrem Verhalten also eher einer Konstante (in C++ beispielsweise mit const bezeichnet, in Java mit final).

Benennung und Referenzierung:
Eine Variable wird mit ihren name-Attribut benannt (der Name ist ein QName, der ein Präfix mit angebundenem Namens­raum besitzen darf). Aufgerufen wird sie ebenfalls über den Namen mit voran­gestelltem $-Zeichen. Dies ist innerhalb jedes XPath-Ausdrucks oder Attribut­wert-Templates möglich:

<xsl:variable name="beispielvariable" select="der_wert"/>
<!-- Referenzierung -->
<xsl:value-of select="$beispielvariable"/>

Achtung – bei Referenzierung kein Unterschied zu xsl:param:
Bei der Referenzierung im XPath-Ausdruck bzw. AVT wird nicht zwischen Variablen und Parametern unterschieden. Ob beispielsweise $x mittels <xsl:variable name="x"> oder <xsl:param name="x"> deklariert wurde, ist an der Referenz nicht erkennbar. Aus diesem Grund treten Kolli­sionen und Shadowing auch zwischen namensgleichen Variablen und Para­metern auf.

Gültigkeitsbereich (Scope) von Variablen:
In XSLT haben Variablen einen streng reglementierten Gültigkeitsbereich (scope). Innerhalb dieses Gültigkeits­bereichs können sie ausgelesen werden – außerhalb davon sind sie nicht sicht­bar (bzw. gar nicht existent).

Hintergrund ist, dass ein Stylesheet und jede seiner Template-Regeln sequenzi­ell abgearbeitet wird. Der Prozessor liest nicht »voraus«, um eventuelle Variab­lendeklarationen kennen zu lernen, und er geht nicht »zurück«, um nachträg­lich eine Variablenreferenz an einer Stelle vor ihrer Deklaration einzusetzen.

Hinweis – Faustregel für den Gültigkeitsbereich einer Variable:
Eine Variable ist gültig (in Scope) ab dem Punkt ihrer Deklaration für alle folgenden Elemente gleicher Hierarchieebene (following siblings) und ihre Nachfolgerelemente (descen­dants).

Hier ein kurzes Beispiel zur Verdeutlichung des Gültigkeitsbereichs: Oft wird versucht, in Abhängigkeit von äußeren Bedingungen eine Variable mit zwei unterschiedlichen Werten zu belegen. Auf folgende Weise geht dies nicht:

...
<xsl:choose>
  <xsl:when test="bedingung1">
    <xsl:variable name="so_nicht" select="wert1"/>
  </xsl:when>
  <xsl:when test="bedingung2">
    <xsl:variable name="so_nicht" select="wert2"/>
  </xsl:when>
</xsl:choose>
...
<!-- die Referenzierung von $so_nicht schlägt fehl: -->
<xsl:value-of select="$so_nicht"/>

Die Variable innerhalb der xsl:when-Instruktionen unterschiedlich zu dekla­rieren, ist zwar legal, erreicht das Ziel in diesem Fall jedoch nicht: Zum Zeit­punkt des Versuchs ihrer Referenzierung ist die Variable $so_nicht bereits außerhalb ihres Scopes – man könnte sie nach der following-sibling-Regel nur innerhalb der jeweiligen xsl:when-Container referenzieren.

Anmerkung: Eine funktionierende Variante, einer Variable alternativ verschiedene Werte zuzuweisen, ist in Beispiel 1 beschrieben.

Anhand des Gültigkeitsbereichs der Variable im Stylesheet unterscheidet man zwischen globalen und lokalen Variablen. Entscheidend hierfür ist der Ort der Deklaration.

Globale Variablen

Um überall im Stylesheet auslesbar zu sein muss xsl:variable im Stylesheet als Toplevel-Element erscheinen. Geschickter­weise stellt man die Variablendeklaration möglichst an den Beginn des Sty­lesheets, woraufhin sie für alle folgenden Elemente und deren Child-Ele­mente gültig ist. Mit anderen Worten, da ja alle xsl:template-Elemente fol­lowing-siblings der Variablendeklaration sind, gilt die Variable in allen folgenden Templates:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:variable name="var_global" select="'der_wert'"/>
  <!-- Referenzierung überall im Stylesheet mit $var_global -->
</xsl:stylesheet>

Eine Ausnahme bei der Referenzierungsmöglichkeit globaler Variablenwerte bilden diejenigen Template-Regeln, innerhalb derer eine gleich benannte lokale Variable (oder ein gleich benannte lokaler Parameter!) definiert ist. Diese überschattet die globale Variable. Der globale Wert ist innerhalb dieser Template-Regel daher nicht erreichbar.

Lokale Variablen

Wird eine Variable innerhalb einer Template-Regel xsl:template deklariert, so gilt sie lokal innerhalb dieser Template-Regel, während diese aktiv ist. Ihr Scope ist also auf »ihren« Templateblock beschränkt – und dort auf die der Deklaration folgenden Geschwisterele­mente. Aus diesem Grund deklariert man sie am besten direkt zu Beginn der Template-Regel (jedoch nach lokalen Parametern).

Ihre Reihenfolge spielt weder für die Wertübergabe noch für die Referenzie­rung der Werte eine Rolle.

<xsl:template match="beispiel">
  <!-- hier evtl. lokale Parameter -->
  <xsl:variable name="var1" select="'wert_1'"/>
  <xsl:variable name="varm2" select="'wert_2'"/>
  ...
  <!-- Referenzierung mit $var1 und $var2 -->
</xsl:template>

Eine lokale Variable wird bei jedem Aufruf der Template-Regel, in der sie gilt, initialisiert und ihr Wert neu erzeugt. Dieser Wert gilt unverändert während der Laufzeit der Template-Regel. Vor und nach der Instanziierung der Templa­te-Regel ist eine lokale Variable nicht existent und ist aus diesem Grunde außerhalb der Template-Regel nicht zugänglich.

Es ist gefahrlos möglich, in anderen Template-Regeln gleich benannte lokale Variablen zu verwenden, da sich ihre Gültigkeitsbereiche nicht überlappen können. Existiert eine namensgleiche globale Variable (bzw. ein globaler Parameter), so besitzt die lokale innerhalb ihrer Template-Regel Vorrang.

Referenz in einer anderen Variablendeklaration:
Es ist möglich, den Wert einer Variable als Referenz bei der Wertermittlung der Deklaration einer weite­ren Variable einzusetzen. Bei globalen Variablen ist dabei ihre Reihenfolge zu beachten: Soll die Variable $a mit ihrem Wert bei der Deklaration der Variablen $b eingesetzt werden, so muss sie zu diesem Zeitpunkt bereits deklariert sein (da sie sonst nicht referenziert werden kann):

<xsl:variable name="b" select="$a * 2"/>

Es dürfen keine zirkulären Definitionen auftreten. Allerdings kann eine Vari­able ohnehin nicht innerhalb ihrer eigenen Deklaration bzw. innerhalb ihres eigenen, ihren Wert generierenden Templateblocks referenziert werden, da sie dort nicht im Scope ist.

Beispiele:

Beispiel 1 – Einer Variable alternative Werte zuweisen:

<!-- Lösung mit XSLT 1.0 -->
<xsl:variable name="maximum">
  <xsl:choose>
    <xsl:when test="$wert1 &gt; $wert2">
      <xsl:value-of select="$wert1"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$wert2"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

Dies ist die XSLT 1.0 Methode, einer Variable $maximum alternativ zwei Werte $wert1 oder $wert2 zuzuweisen. Sie funktioniert ebenfalls mit XSLT 2.0, ist allerdings verhältnismäßig umfangreich in der Formulierung.

Der xsl:choose-Block muss sich in der Variableninstruktion befinden. Es ist nicht möglich, alternative Variablendeklarationen beispielsweise im Inneren der xsl:when-Instruktionen unterzubringen und so zwischen ihnen zu wählen.

Für dieses (spezielle) Problem ist in XSLT 2.0 eine einfachere Lösung möglich, die anstelle des xsl:choose einen XPath-Ausdruck verwendet:

<!-- Lösung mit XPath 2.0 -->
<xsl:variable name="maximum" select="if($wert1 &gt; $wert2) then $wert1 else $wert2"/>

Diese Lösung ist allerdings nicht abwärtskompatibel. Eine weitere Vereinfa­chung erzielt man durch Einsatz der XPath 2.0-Funktion fn:max():

<!-- Lösung mit XPath 2.0 -->
<xsl:variable name="maximum" select="fn:max(($wert1, $wert2))"/>

wobei auch das Maximum aus einer Sequenz $eingabesequenz mit einer beliebigen Anzahl von Werten zurückgegeben und nicht – wie hier – nur zwi­schen zwei Werten gewählt werden kann:

<!-- allgemeine Lösung mit XPath 2.0 -->
<xsl:variable name="maximum" select="fn:max($eingabesequenz)"/>
  

Beispiel 2 – Beispiel für eine globale Variable:

<xsl:variable name="ausrichtung">center</xsl:variable>
<!-- eine von vielen Template-Regeln -->
<xsl:template match="abschnitt">
  <p align="{$ausrichtung}"><xsl:apply-templates/></p>
</xsl:template>

Hier wird eine globale Variable $ausrichtung deklariert, die in einem Attribut­-Template eines Literal Result Elements einer Template-Regel referenziert wird. Außer in dieser einen Template-Regel wäre die Variable auch in allen anderen Template-Regeln des Stylesheets gültig.

Soll die Ausrichtung der <p>-Container global geändert werden, so müsste nur der Wert der Variable im Stylesheet geändert werden. (Soll dies von außen während des Aufrufs geschehen, so würde sich alternativ ein globaler Parameter anbieten.)

Beispiel 3 – Shadowing zwischen globaler und lokaler Variable:

<!-- globale Variable -->
<xsl:variable name="die_variable" select="globaler_wert"/>
<xsl:template name="template_a">
  <xsl:variable name="die_variable" select="lokaler_wert"/>
  ...
  <!-- Referenz bezieht sich auf lokale Variable: -->
  Lokal: <xsl:value-of select="$die_variable"/>
</xsl:template>
<xsl:template name="template_b">
  <!-- Referenz bezieht sich auf globale Variable: -->
  Global: <xsl:value-of select="$die_variable"/>
</xsl:template>

Hier ist eine Variable $die_variable sowohl global deklarariert als auch lokal in einer Template-Regel. Innerhalb dieser Template-Regel ist nur der Wert der lokalen Variable referenzierbar (shadowing). Es gibt dort keinerlei Möglichkeit, auf den globalen Wert zuzugreifen.

Beispiel 4 – Zwischenwerte in lokale Variablen speichern:

<xsl:template name="listenausgabe">
  <xsl:param name="liste"/>
  <xsl:variable name="token" select="fn:substring-before($liste, ' ')"/>
  <xsl:variable name="rest" select="fn:substring-after($liste, ' ')"/>
  <!-- der erste Teil der Liste wird ausgegeben: -->
  <xsl:value-of select="$token"/>
  <!-- prüfen, ob Rest geblieben ist ... -->
  <xsl:if test="$rest">
    <!-- Break ausgeben: -->
    <br/>
    <!-- ... und Template wieder aufrufen: --> 
    <xsl:call-template name="listenausgabe">
      <!-- Rest der Liste als neuen Anfangswert übergeben: -->
      <xsl:with-param name="liste" select="$rest"/>
    </xsl:call-template>
  </xsl:if>
<xsl:template>

Hier werden die Ergebnisse von zwei String-Operationen in lokale Variablen gespeichert und anschließend mehrmals in derselben Template-Regel verwen­det. Man könnte auf die Variablen verzichten, müsste dann aber denselben Ausdruck mehrmals auswerten lassen.

Dies ist ein Ausschnitt aus einem Stylesheet zur rekursiven Verarbeitung eines Strings. Das vollständige Beispiel befindet sich als Beispiel 2 bei den Erläute­rungen zur Funktion fn:substring-after().

Beispiel 5 – Simulation eines Zählers:

<xsl:template name="zaehler">
  <!-- beim Start ist der Zähler 0: -->
  <xsl:param name="der_zaehler" select="0"/>
  <!-- neue Variable – hier wird gezählt: -->
  <xsl:variable name="neuer_zaehler" select="$der_zaehler + 1"/>
  <!-- Abbruchbedingung prüfen: -->
  <xsl:if test="$neuer_zaehler &lt; 10">
    <ausgabe>Der Zählerstand ist <xsl:value-of select="$neuer_zaehler"/></ausgabe>
    <!-- Template wieder aufrufen -->
    <xsl:call-template name="zaehler">
      <!-- den Zählerstand übergeben: -->
      <xsl:with-param name="der_zaehler" select="$neuer_zaehler"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

Die Iteration eines Zählers kann man durch Rekursion simulieren. Dazu muss ein benanntes Template sich selbst aufrufen und sich selbst den letzten Zähler­stand als Eingabeparameter übergeben.

Ganz wichtig ist die xsl:if-Bedingung oder eine ähnliche Konstruktion am Ende. Nur so kann man eine »Endlosschleife« verhindern, in der sich das Tem­plate unaufhörlich immer wieder selbst aufruft. Es muss also eine Abbruchbe­dingung formuliert werden. (Die gleiche Vorsichtsmaßnahme ist bei jeder Programmiersprache in while- oder do ... while-Schleifen erforderlich.)

Beispiel 6 – Speicherung einer Dokumentreferenz in einer Variablen:

<xsl:variable name="das_dokument" select="docu¬ment('extern.xml')"/>
<xsl:template name="externes_dokument">
  <!-- Zugriff auf das Dokument -->
  <xsl:apply-templates select="$das_dokument"/>
</xsl:template>

Auf das in der Variablen $das_dokument gespeicherte Dokument können kann genauso zugegriffen werden wie auf das direkt mit document('extern.xml') referenzierte. Es ist daher praktisch, ein häufig benötigtes Dokument in einer Variablen – eventuell wie hier in einer globalen – parat zu haben.

Elementdefinition:

XSLT 1.0:

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

     <!-- Content: template -->
</xsl:variable>

XSLT 2.0:

<!-- Category: declaration/instruction -->
<xsl:variable
     name = qname
     select? = expression
     as? = sequence-type>

    <!-- Content: sequence-constructor -->
</xsl:variable>
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