Vorige Seite     Hauptseite     Nächste Seite


Informationsstrukturierung: Mo, 18.06.2012

XSLT III. Variable, Parameter und Modi.

Variable

Ein Variable wird wie folgt vereinbart.
<xsl:variable
  name = qname
  select? = xpath-ausdruck
  as? = typ>
  <!-- Wert-->
</xsl:variable
Der Name ist der Name der Variablen. Dies hat den Typ eines QName, das heißt ein qualified name. Für unsere Zwecke reicht es zu sagen, dass dies eine Zeichenkette ist. Haben wir eine Variable namens theo definiert, so bekommen wir den Wert der Variablen durch $theo. Das Attribut as erlaubt, den Typ zu spezifizieren. Man kann Variable von jedem Typ haben; der default ist allerdings string. Man ist gut beraten, den Typ anzugeben. Der Wert, der der Variablen zugewiesen wird, ist entweder der Wert des in dem Tag eingeschlossenen Knotens, also zB
<xsl:variable
  as ="xs:int">
  137
</xsl:variable>
Oder der Wert bestimmt sich durch Auswertung des select Ausdrucks. Es darf deswegen nicht gleichzeitig ein select Attribut vorhanden sein und der Knoten nicht leer. Denn dann gibt es einen Konflikt zwischen zwei Zuweisungen. Allerdings dürfen beide leer sein. In diesem Fall hat die Variable den Wert einer leeren Zeichenkette. Ich gebe hier ein instruktives Beispiel. Um die im Prozessor verankerten Alphabetreihenfolgen zu tabellieren, habe ich eine Datei geschrieben, die einfach nur die Buchstaben in irgendeiner Reihenfolge enthält, etwa so.
<?xml version="1.0"
<alphabet>
<wort>c</wort>
<wort>b</wort>
<wort>q</wort>
</alphabet>
Das eigentlich Spannende ist die Transformationsdatei.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
  <xsl:variable name="orig" select="/alphabet/wort" as="xs:string*"/>
  <xsl:variable name="ger" as="xs:string*">
    <xsl:perform-sort select="$orig">
      <xsl:sort lang="de-DE"/>
    </xsl:perform-sort>
  </xsl:variable>
  <xsl:variable name="hun" as="xs:string*">
    <xsl:perform-sort select="$orig">
      <xsl:sort lang="hu-HU"/>
    </xsl:perform-sort>
  </xsl:variable>
  <xsl:template match="/alphabet">
    <html>
       <head></head>
       <body bgcolor="moccasin">
         <h3>Das Alphabet</h3>
         <table border="3">
           <tr><td>Pos.</td><td>Original</td>
              <td>de-De</td><td>hu-HU</td></tr>
           <xsl:for-each select="$orig">
             <xsl:variable name="i" select="position()"/>
             <tr><td> <xsl:number value="$i" format="1."/></td>
                <td><xsl:value-of select="$orig[$i]"/></td>
                <td><xsl:value-of select="$ger[$i]"/></td>
                <td><xsl:value-of select="$hun[$i]"/></td>
             </tr>
           </xsl:for-each>
         </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
Die Testdatei ordnet auch nach finnischer Alphabetordnung. Ich habe das mit Saxon 9.1.0.5 getestet und es funktioniert. Als Ergebnis bekommt man die Buchstaben zunächst unsortiert, dann nach verschiedenen Länderkonventionen sortiert ausgegeben. Der Clou ist, dass die Ausgabe senkrecht erfolgt. Damit das geht, habe ich von xsl:perform-sort Gebrauch gemacht. Dies erlaubt, eine Liste zu ordnen. Das Ergebnis ist wieder eine Liste, und diese weise ich einer Variablen zu. Das Attribut as mit Wert xs:string* darf hier nicht fehlen, sonst denkt das Programm, ich will nur eine Zeichenkette. (Der Stern * ist ein sogenannter Typkonstruktor. typ* bezeichnet Listen von Objekten vom Typ typ.) Anschließend gehe ich synchron durch alle Listen durch. Dabei wird eine Variable i lokal vereinbart und mit dem Wert position() versehen. Der Wert wird dann ausgegeben und anschließend jeder Liste witergegeben. (Auch hier wieder: ohne die Variable geht's nicht, das habe ich probiert.) Man kann auch noch die Möglichkeiten einer Formatierung von Zahlausgaben anschauen.

Skopus

Hat man eine Variable, sagen wir x7, deklariert und ihr einen Wert zugewiesen, etwa 123, so kann man auf diesen Wert anschließend zurückgreifen. Den Wert bekommt man mittels $x7. Klarerweise ist der Wert der Variable nicht verfügbar, bevor sie definiert wurde (es sei denn, sie ist global). Jedoch ist die Variable nicht unbegrenzt danach existent sondern besitzt eine gewisse Lebensspanne, den sogenannten Skopus. In XSLT ist der Skopus einer Variable durch das Tag begrenzt, in dem die Variable definiert worden ist. Das bedeutet: ist die Variable unmittelbar nach einem Tag namens <tag> deklariert worden, dann endet der Skopus beim nächsten Auftreten von </tag>. Innerhalb ihres Skopus darf die Variable nicht erneut definiert werden, das ergibt eine Fehlermeldung. In XSLT kann man den Wert einer Variablen nicht ändern, deswegen ist der Skopus ein wichtiges Instrument, um eine Variable tatsächlich variabel zu halten. Hier ist die Idee. Gesetzt, wir wollen eine Tabelle in HTML Format ausgeben. Wir wollen einen gewissen Wert, sagen wir die Zeilennummer, in einer Zeile verfügbar machen. Da sich die Zeilennummer ständig ändert, darf man die Variable nicht global vereinbaren. Denn dann wird ihr ein Wert zugewiesen, der nicht mehr zu ändern ist. Die Lösung besteht hier darin, die Variable erst nach dem Tag <tr> zu vereinbaren. In diesem Fall wird ihr Wert für die gesamte Zeile (also bis zum nächsten </tr>) zur Verfügung stehen. Man kann das in der oberen Datei sehr schön sehen. Innerhalb von <for-each> wir die Variable i dem Wert von position() zugewiesen. Endet das Tag, dann wird ein neuer Knoten bearbeitet, die Variable i wird dann aber nicht neu zugewiesen: es ist lediglich so, dass mit Ende des ersten Zyklus die Variable i verschwindet und mit Beginn des neuen Zyklus eine neue Variable i entsteht. Ihr Wert ist dann der Wert von position(), welcher nunmehr anders ist als der vorige.

Parameter

Parameter sind fast dasselbe wie Variable. Sie haben allerdings die Eigenschaft, dass sie ihre Werte anders bekommen (können). Es gibt drei Sorten Parameter. Der einfachste Typ ist der eines Funktionsparameters; ich bespreche ihn allerdings zusammen mit Funktionen. Stylesheet parameter sind Größen, die man dem Stylesheet zum Zeitpunkt des Aufrufs übergeben kann. Der Wert steht also nicht in dem Stylesheet sondern darf zum Zeitpunkt des Aufrufs festgelegt werden. (oxygen erlaubt natürlich, diese Werte festzulegen.) Hier ist die Syntax.
<xsl:param
  name = qname
  select? = xpath-ausdruck
  as? = typ
  required? = "yes" | "no">
  <!-- Wert-->
</xsl:param>
Der einzige Unterschied zu xsl:variable ist die Möglichkeit festzulegen, ob der Parameter einen Wert haben muss. Es gelten wiederum die Regeln wie bei Variablen: es darf nicht gleichzeitig das Tag nichtleer sein und select anwesend. Allerdings dürfen diesmal beide leer sein, da der Wert ja noch nicht festliegen muss. Bei Templates haben wir noch eine Option mehr:
<xsl:param
  name = qname
  select = xpath-ausdruck
  as? = typ
  required? = "yes" | "no"
  tunnel? = "yes" | "no">
  <!-- Wert-->
</xsl:param>
Falls tunnel auf yes gesetzt wird, dann wird der Parameter an alle untergeordneten Prozeduren weitergereicht. Das ist sehr nützlich, wenn man sich eine Prozedur schreiben will, die verschiedene Stile der Ausgabe hat.

Modi

Modi dienen zur Auswahl von Templates. Wir können Templates zu gewissen Modi gruppieren um dann beim Aufruf <xsl:apply-templates> einen Modus anzugeben. Wenn wir also beim Aufruf den Modus spezifizieren, werden nur Templates verwendet, die zu diesem Modus gehören. Zusätzlich zu den frei verfügbaren Namen existieren drei spezielle "Modi":

Die Befehle <xsl:apply-templates> und <xsl:template> besitzen je ein Attribut namens mode. Der Wert von mode in <xsl:template> darf eine Liste von Modi sein (darunter #default) oder #all. Der Wert von mode in <xsl:apply-templates> hingegen darf nur ein einziger Modus sein oder #current. Man beachte also, dass Templates in mehrere Modi gruppiert werden können, aber der Aufruf nur einen einzigen Modus verwendet. Man mag sich überlegen, dass es nicht nötig ist, beim Aufruf die Angabe von Listen von Modi anzugeben. Den Effekt kann man durch die Einführung eines neuen Modus erreichen, der alle in der Liste gegebenen Modi zusammenfasst. So zum Beispiel ist #all ein alles umfassender Modus.

Ist der Modus beim Template nicht gesetzt, wird der Wert #default eingesetzt. Das bedeutet, dass dieses Template immer dann verwendet wird, wenn in <xsl:apply-templates> kein Modus angegeben ist. Ist hingegen der Modus gesetzt und enthält er nicht #default, dann kann es nur dann werwendet werden, wenn <xsl:apply-templates> einen Modus aufruft, der in der Liste vorkommt. Sollte ein Template einen Modus haben, der niemals aufgerufen wird, so ist das kein Fehler. Es bedeutet lediglich, dass das Template niemals angewendet wird (eine gute Möglichkeit, um Templates zeitweilig zu inaktivieren, ohne den Code stark zu verändern).

Man sollte wissen, dass der Aufruf von <xsl:apply-templates> dazu führt, dass der XSLT-Prozessor versucht, ein geeignetes Template zu finden. Dabei gibt es mehrere Sonderfälle:


Vorige Seite     Hauptseite     Nächste Seite