Gern stehe ich zur fachlichen Unterstützung in XML-Technologien, C#.NET, VisualBasic.NET und Java zur Verfügung. Sprechen Sie mich einfach an: Mail oder ☎ 0151 . 750 360 61


XSL-Übersicht / xsl:variable

xsl:variable

xsl:variable

➪ Im XSL übernimmt eine Variable einen temporären Inhalt, der in der Regel zur Laufzeit gesetzt und an passender anderer Stelle wieder ausgelesen wird.

Auf dieser Seite:

Dieser temporäre Inhalt kann ein einzelner Wert, eine Liste simplen Datentyps sein, ebenso ein externes XML-Dokument (document()), ein komplexer Baum, das Zwischenergebnis einer mehrstufigen Konvertierung: Mithin eine komplexe Sequenz (xsl:sequence) von Items.


<xsl:variable name="v4">4</xsl:variable>

So enthält die Variable v4 konstant den Wert 4, und exakt dieser Wert wird auch ausgegeben.


<xsl:template match="/">
    <ergebnis>
      <xsl:value-of select="$v4"/>
    <ergebnis>
</xsl:template>

Rechnen mit xsl:variable

Selbstverständlich können Sie mit xsl:variable auch rechnen: Addieren, Subtrahieren, Multiplizieren, Dividieren. Hierbei sollten Sie aber berücksichtigen, dass diverse XSL-Prozessoren Zahlenwerte automatisch als xs:double einstufen, wodurch korrekte Ergebnisse nur annähernd ermittelt werden. Ein Beispiel:


<xsl:variable name="va">11</xsl:variable>
<xsl:variable name="vb">12.99</xsl:variable>
<xsl:variable name="vc" select="$va * $vb"/>
<xsl:template match="/">
    <ergebnis>
        <xsl:value-of select="$vc"/>
    </ergebnis>
</xsl:template>

Das Resultat lautet nicht auf 142.89, sondern:


<ergebnis>142.89000000000001</ergebnis>

Wenn Sie exakte Werte benötigen, ist die Arbeit in XSLT 2.0 / XSLT 3.0 sowie die dort mögliche Typkontrolle zweckmäßiger:


<xsl:variable name="va" as="xs:integer">11</xsl:variable>
<xsl:variable name="vb" as="xs:decimal">12.99</xsl:variable>
<xsl:variable name="vc" select="$va * $vb" as="xs:decimal"/>

alternativ:


<xsl:variable name="va">11</xsl:variable>
<xsl:variable name="vb">12.99</xsl:variable>
<xsl:variable 
     name="vc" 
     select="xs:integer($va) * xs:decimal($vb)" 
     as="xs:decimal"/>
<xsl:template match="/">
    <ergebnis>
        <xsl:value-of select="$vc"/>
    </ergebnis>
</xsl:template>
</xsl:stylesheet>

oder (als ) unter XSLT 3.0:


<xsl:variable name="va">11</xsl:variable>
<xsl:variable name="vb">12.99</xsl:variable>
<xsl:variable 
     name="vc" 
     select="function($x as xs:integer, $y as xs:decimal) 
     as xs:decimal
     {$x * $y}"/>
<xsl:template match="/">
    <ergebnis>
        <xsl:value-of select="$vc($va, $vb)"/>
    </ergebnis>
</xsl:template>

Das (nunmehr korrekte) Resultat lautet:


<ergebnis>142.89</ergebnis>

xsl:variable als komplexe Nodelist

Eine xsl:variable kann auch eine Nodeliste bzw. einen Node-Set umfassen.


<xsl:variable name="v3">
    <value1>11</value1>
    <value2>22</value2>
    <value3>33</value3>
</xsl:variable>

Die Verarbeitung von xsl:variable als Node-Sets ist prozessorabhängig: Einige kommen problemlos damit klar, andere benötigen die separate Einbindung spezieller Namespaces. Beispiele hierzu finden Sie in . Hier finden Sie die Verarbeitung mit Xalan:


<xsl:stylesheet 
  xmlns:xalan="http://xml.apache.org/xalan" 
  xmlns:common="http://exslt.org/common"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  version="1.0">
  <xsl:template match="/">
    <ergebnis>      
      <xsl:for-each 
           select="common:node-set($v3)/child::*">
        <xsl:sort 
             select="." 
             data-type="number" 
             order="descending"/>
        <ee>
          <nr><xsl:value-of select="position()"/></nr>
          <name><xsl:value-of select="name()"/></name>
          <wert><xsl:value-of select="."/></wert>
        </ee>
      </xsl:for-each>
    </ergebnis>
  </xsl:template>
</xsl:stylesheet>

Das Resultat lautet (die Nummerierung beginnt mit 1):


<ergebnis 
   xmlns:common="http://exslt.org/common" 
   xmlns:xalan="http://xml.apache.org/xalan" >
  <ee>
    <nr>1</nr>
    <name>value3</name>
    <wert>33</wert>
  </ee>
  <ee>
    <nr>2</nr>
    <name>value2</name>
    <wert>22</wert>
  </ee>
  <ee>
    <nr>3</nr>
    <name>value1</name>
    <wert>11</wert>
  </ee>
</ergebnis>

Inkrementelle Anpassung der xsl:variable

Im Unterschied zu zustandsabhängigen Variablen in C, C++, C#.NET, Java, VB.NET und zahlreichen anderen Programmiersprachen, in denen x = x + 1 eine durchaus sinnvolle Anweisung ist, übernimmt eine xsl:variable nur einen temporären Wert, der in der Regel zur Laufzeit gesetzt und anderswo wieder ausgelesen wird.

Nicht vorgesehen ist daher eine inkrementelle Statusänderung der xsl:variable, wie sie beispielsweise mit der automatischen Nummerierung von Ergebnissen verbunden ist. Derlei Aufgabenstellungen sind im Regelfall über oder lösbar. In XSLT 3.0 steht darüber hinaus zur Verfügung.

In direktem Anschluss an das vorherige Beispiel (xsl:variable als komplexe Nodelist, dieses Mal jedoch berechnet mit einem XSLT 3.0-fähigen XSL-Prozessor) finden Sie hier einen xsl:accumulator, der einen Startwert von 7 unterstellt und anschliessend die Childnodes von $v3 durchnummeriert.


<xsl:variable name="v3">
    <value1>11</value1>
    <value2>22</value2>
    <value3>33</value3>
</xsl:variable>
<xsl:accumulator 
     name="increment" 
     initial-value="7" 
     as="xs:integer">
     <xsl:accumulator-rule 
          match="$v3/child::*" 
          select="$value + 1"/>
</xsl:accumulator>
<xsl:template match="/">
  <ergebnis>    
    <xsl:for-each select="$v3/child::*">      
      <ee>
        <nr>
          <xsl:value-of 
               select="accumulator-after('increment')"/>
        </nr>
        <name><xsl:value-of select="name()"/></name>
        <wert><xsl:value-of select="."/></wert>
      </ee>
    </xsl:for-each>
  </ergebnis>
</xsl:template>

Das Resultat lautet (die Nummerierung beginnt mit 8):


<ergebnis>
   <ee>
      <nr>8</nr>
      <name>value1</name>
      <wert>11</wert>
   </ee>
   <ee>
      <nr>9</nr>
      <name>value2</name>
      <wert>22</wert>
   </ee>
   <ee>
      <nr>10</nr>
      <name>value3</name>
      <wert>33</wert>
   </ee>
</ergebnis>

Attribut-Atomisierung mit data

Die -Funktion liefert die atomisierten Werte einer Sequenz: Hier verwende ich sie für die jedes adressierten Elements.


<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
    version="2.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:variable name="v3">
    <value1 att12="12" att13="13">11</value1>
    <value2 att22="22" att23="23">22</value2>
    <value3 att22="32" att33="33">33</value3>
  </xsl:variable>
  <xsl:template match="/">
    <ergebnis>    
      <xsl:for-each select="$v3/child::*">
        <xsl:variable 
             name="vdata" 
             select="data(./attribute::*)"/> 
        <ee  content="{./text()}" 
             nodename="{name(.)}">        
          <xsl:value-of select="$vdata"/>
        </ee>
      </xsl:for-each>
    </ergebnis>
  </xsl:template>
</xsl:stylesheet>

Das Resultat lautet:


<ergebnis>
   <ee content="11" nodename="value1">12 13</ee>
   <ee content="22" nodename="value2">22 23</ee>
   <ee content="33" nodename="value3">32 33</ee>
</ergebnis>

Dasselbe Ergebnis können Sie alternativ mit dem -Attribut von xsl:value-of erreichen:


<ergebnis>
  <xsl:for-each select="$v3/child::*">
    <ee content="{./text()}" nodename="{name(.)}">        
      <xsl:value-of 
           select="./attribute::*" 
           separator=" "/>
    </ee>
  </xsl:for-each>
</ergebnis>

Externe XML-Dokumente als xsl:variable

Mit der document-Funktion können Sie auch ein externen XML-Dokumente in einer xsl:variable abbilden.


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">
  <xsl:output method="xml" indent="yes" />

Über die document-Funktion können externe XML-Dokumente (die ausdrücklich nicht Teil des XML-Inputs sind) in eine Variable eingelesen werden. Damit umfasst die Variable $vinput beispielsweise einen komplexen XML-Baum oder eine Textdatei.


<xsl:variable name="vinput"
     select="document('Orte_Elemente.xml')" />

$var1 greift auf den $vinput zu; durch die gezielte XPath-Adressierung beinhaltet $var1 einen normalen Textinhalt.


<xsl:variable name="var1"
     select="$vinput/Orte/Ort[1]/Mensch[2]/Kauf[3]/bez/text()" />

$var2 greift ebenfalls auf $vinput zu. Der Inhalt umfasst ein einziges Element, das seinerseits mehrere Childnodes in sich birgt. Um diese anzusteuern, ist in XPath $var2/Kauf/child::* erforderlich. Die Einzelinformation erhalten Sie über $var2/Kauf/bez.


<xsl:variable name="var2">
    <xsl:copy-of 
         select="$vinput/Orte/Ort[1]/Mensch[2]/Kauf[3]" />
</xsl:variable>

$var3 greift ebenfalls auf $vinput zu. Bedingt durch die XPath-Adressierung, umfasst $var3 mehrere Childnodes: Hier werden mehrere Childnodes direkt zugewiesen, ohne das kapselnde Element Kauf. Angesteuert werden können diese im Loop über $var3/child::*. Die Einzelinformation erhalten Sie über $var3/bez.


<xsl:variable name="var3">
 <xsl:for-each 
    select="$vinput/Orte/Ort[1]/Mensch[2]/Kauf[3]/child::*">
      <xsl:copy-of select="." />
 </xsl:for-each>
</xsl:variable>

Das benannte Template NodeInfo untersucht den jeweils aktuellen Node/Kontext aus verschiedener Sicht. Das Template NodeInfo umfasst keine Parameterzuweisung, sondern bekommt den Kontext ausschließlich zur zugewiesen.


<xsl:template name="NodeInfo">
  <xsl:attribute 
       name="Elementname" 
       select="./local-name()" />
  <xsl:attribute 
       name="wert" 
       select="." />
  <xsl:attribute name="Nodetype">
    <xsl:choose>
     <xsl:when test="./self::text()">Textnode</xsl:when>
     <xsl:when test="./self::element()">Elementnode</xsl:when>
     <xsl:when test="./self::comment()">Kommentarknoten</xsl:when>
    </xsl:choose>
  </xsl:attribute>
  <xsl:attribute name="XSDtype">
   <xsl:choose>
   <xsl:when test=". castable as xs:integer">xs:integer</xsl:when>
   <xsl:when test=". castable as xs:decimal">xs:decimal</xsl:when>
   <xsl:when test=". castable as xs:string">xs:string</xsl:when>
   </xsl:choose>
  </xsl:attribute>
</xsl:template>

<xsl:template match="/"> definiert in diesem Fall den Programmstart. Hier werden die vorher deklarierten Variablen angesprochen und jedes ihrer Childnodes über eine Schleife dem vorher benannten Template NodeInfo übergeben, das die restliche Arbeit übernimmt.


 <xsl:template match="/">
  <ergebnis>
   <var1>
    <xsl:for-each select="$var1/self::text()">
     <xsl:call-template name="NodeInfo" />
    </xsl:for-each>
   </var1>
   <var2>
    <xsl:for-each select="$var2/Kauf/child::*">
     <childelement>
      <xsl:call-template name="NodeInfo" />
     </childelement>
    </xsl:for-each>
   </var2>
   <var2bez>
    <xsl:value-of select="$var2/Kauf/bez"/>
   </var2bez>
   <var3>
    <xsl:for-each select="$var3/child::*">
     <childelement>
      <xsl:call-template name="NodeInfo" />
     </childelement>
    </xsl:for-each>
   </var3>
   <var3bez>
    <xsl:value-of select="$var3/bez"/>
   </var3bez>
  </ergebnis>
 </xsl:template>
</xsl:stylesheet>

xsl:sequence

Eine weitere Alternative zur Variablendeklaration bietet xsl:sequence:


<xsl:variable name="vsequence">
  <xsl:sequence select="//Mensch/vorname"/>
</xsl:variable>
<xsl:for-each select="$vsequence/child::*">
  <vn>
    <xsl:value-of select="."/>
  </vn>
</xsl:for-each>  

Wie , ist es sinnvoll, sich über den Datentyp von Variablen jeweils genau im Klaren zu sein, um Programmierfehler mit weitreichenden Konsequenzen zu vermeiden. Siehe auch: Arbeit mit temporären Bäumen.

Anonyme Funktionen

In XSL 3.0 ist es auch möglich, eine Variable als zu deklarieren.

wg / 15. September 2018



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/xsl_variablen.html