XML * XML-SCHEMA * XPATH * XSL * XSL-FO * SVG * XQUERY * XPROC * ANT * DIVERSES



XSL / Die XSLT - Struktur / xsl:number

xsl:number

xsl:number

xsl:number bietet erweiterte, selektive wie hierarchische Möglichkeiten zur Nummerierung von Elementen.

Auf dieser Seite:

Siehe .

xsl:number in 1.0


<xsl:number
  level = "single" | "multiple" | "any"
  count = pattern
  from = pattern
  value = number-expression
  format = { string }
  lang = { nmtoken }
  letter-value = { "alphabetic" | "traditional" }
  grouping-separator = { char }
  grouping-size = { number } />

Siehe auch https://www.w3.org/TR/xslt-10/#element-number.

xsl:number in 2.0


<xsl:number
  value? = expression
  select? = expression
  level? = "single" | "multiple" | "any"
  count? = pattern
  from? = pattern
  format? = { string }
  lang? = { nmtoken }
  letter-value? = { "alphabetic" | "traditional" }
  ordinal? = { string }
  grouping-separator? = { char }
  grouping-size? = { number } />

Siehe auch https://www.w3.org/TR/xslt20/#element-number.

xsl:number in 3.0


<xsl:number
  value? = expression
  select? = expression
  level? = "single" | "multiple" | "any"
  count? = pattern
  from? = pattern
  format? = { string }
  lang? = { language }
  letter-value? = { "alphabetic" | "traditional" }
  ordinal? = { string }
  start-at? = { string }
  grouping-separator? = { char }
  grouping-size? = { integer } />

Siehe auch https://www.w3.org/TR/xslt-30/#element-number.

Selektiv nummerieren mit count

Nehmen Sie ein XML-Dokument, das diesen Aufbau hat:


<ROOT>
  <Einwohner>
   <id>10</id>
   <name>Ruhelos</name>
   <vorname>Rita</vorname>
   <strasse>Hinundweg</strasse>
  </Einwohner>
  <Einwohner>
   <id>3</id>
   <name>Sorglos</name>
   <vorname>Siggi</vorname>
   <strasse>Nixwieweg</strasse>
  </Einwohner>
...
</ROOT>

Die folgende Logik gibt alle strasse-Nodes aus. Mit dem count-Attribut sorgt xsl:number dafür, dass nur jene strasse-Nodes nummeriert werden, deren Textinhalt 'Hinundweg' ist.


<xsl:template match="/">
  <Ergebnis>
   <xsl:for-each 
        select="/ROOT/Einwohner">
    <Einwohner>
     <xsl:if 
          test="strasse='Hinundweg'">
      <xsl:attribute name="nr">
       <xsl:number 
            count="Einwohner[strasse='Hinundweg']"/>
      </xsl:attribute>
     </xsl:if>
     <strasse>
      <xsl:value-of 
           select="strasse"/>
     </strasse>
    </Einwohner>
   </xsl:for-each>
  </Ergebnis>
</xsl:template>

Wie versprochen: Die Einwohner in 'Nixwieweg' werden nicht nummeriert.


<Ergebnis>
  <Einwohner nr="1">
   <strasse>Hinundweg</strasse>
  </Einwohner>
  <Einwohner>
   <strasse>Nixwieweg</strasse>
  </Einwohner>
  <Einwohner nr="2">
   <strasse>Hinundweg</strasse>
  </Einwohner>
  <Einwohner nr="3">
   <strasse>Hinundweg</strasse>
  </Einwohner>
  <Einwohner>
   <strasse>Nixwieweg</strasse>
  </Einwohner>
  <Einwohner>
   <strasse>Nixwieweg</strasse>
  </Einwohner>
  <Einwohner nr="4">
   <strasse>Hinundweg</strasse>
  </Einwohner>
  <Einwohner nr="5">
   <strasse>Hinundweg</strasse>
  </Einwohner>
</Ergebnis>

Das format-Attribut unterstützt zudem bei der inidividuellen Formatierung.


<xsl:number count="Einwohner[strasse='Hinundweg']" format="a"/>

Dabei gibt es eine ganze Reihe unterschiedlicher Formatierungsmöglichkeiten.

a a, b, c, d, e
A A, B, C, D, E
i i, ii, iii, iv, v
I I, II, III, IV, V
. .1., .2., .3., ...
w eins, zwei, drei, vier, ...
W EINS, ZWEI, DREI, VIER, ...
Ww Eins, Zwei, Drei, Vier, ...

Jedem Element seine ID

Mitunter stehen Sie vor der Aufgabe, jedem Element in einem XML-Dokument eine unique-ID hinzuzufügen, ohne die restliche Struktur des XML-Dokuments zu verändern. In diesem Fall können Sie so vorgehen:


<xsl:template match="*">
  <xsl:element name="{local-name()}">
    <xsl:attribute name="ID">        
      <xsl:number format="1" count="*" level="multiple"/>
    </xsl:attribute>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:element>
</xsl:template>
<xsl:template match="@*">
  <xsl:attribute name="{local-name()}">
    <xsl:value-of select="."/>
  </xsl:attribute>
</xsl:template>
<xsl:template match="text()">
  <xsl:value-of select="."/>
</xsl:template>

Das Ergebnis sieht dann so aus:


<ROOT ID="1">
  <Einwohner ID="1.1">
   <id ID="1.1.1">10</id>
   <name ID="1.1.2">Ruhelos</name>
   <vorname ID="1.1.3">Rita</vorname>
   <strasse ID="1.1.4">Hinundweg</strasse>
  </Einwohner>
  <Einwohner ID="1.2">
   <id ID="1.2.1">3</id>
   <name ID="1.2.2">Sorglos</name>
   <vorname ID="1.2.3">Siggi</vorname>
   <strasse ID="1.2.4">Nixwieweg</strasse>
  </Einwohner>
</ROOT>

Vgl. .

Gezielte Nummerierung mit level="any"

Nehmen Sie einmal dieses XML-Beispieldokument. Hier soll jedes Aktenzeichen-Element ein zusätzliches Attribut nr erhalten, ebenso jedes Element Name, sofern dessen Aktenzeichen einen Wert von mehr als 3500 beinhaltet - beides in aufsteigender Reihenfolge. So geht's:


<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
  version="2.0">  
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/*/root">
    <xsl:apply-templates />
  </xsl:template>
  <xsl:template match="*">
    <xsl:element name="{name()}">
      <xsl:if 
           test="name()='Aktenzeichen' or 
                 (name()='Name' and Aktenzeichen &gt; 3500)">
        <xsl:attribute name="nr">
          <xsl:number 
               count="*[Aktenzeichen &gt; 3500] | 
                        Aktenzeichen" 
               level="any"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Und das ist das Ergebnis:


<root>
   <Nachweis>irgendwo</Nachweis>
   <Name>
      <Bemerkung>LQ</Bemerkung>
      <Aktenzeichen nr="1">1234</Aktenzeichen>
   </Name>
   <Name>
      <Bemerkung>OK</Bemerkung>
      <Aktenzeichen nr="2">2345</Aktenzeichen>
   </Name>
   <Name>
      <Bemerkung>LQ</Bemerkung>
      <Aktenzeichen nr="3">3456</Aktenzeichen>
   </Name>
   <Name nr="4">
      <Bemerkung>LQ</Bemerkung>
      <Aktenzeichen nr="5">4567</Aktenzeichen>
   </Name>
   <Name nr="6">
      <Aktenzeichen nr="7">5678</Aktenzeichen>
   </Name>
   <Name nr="8">
      <Aktenzeichen nr="9">6789</Aktenzeichen>
   </Name>
</root>

Hierarchisch nummerieren mit level="multiple"

Sehr hilfreich ist, die hierarchische Struktur ausgewählter Elemente nummerieren zu können. Das geschieht mit level='multiple'.


 <xsl:template match="/">
  <Ergebnis>
   <xsl:for-each 
        select="/ROOT/descendant-or-self::*">
    <element name="{name()}">
     <xsl:attribute name="nr">
       <xsl:number 
            format="a" 
            count="ROOT | Einwohner | strasse" 
            level="multiple"/>
      </xsl:attribute>
    </element>
   </xsl:for-each>
  </Ergebnis>
 </xsl:template>

Damit ergibt sich eine nachvollziehbare Nummerierung.


<Ergebnis>
  <element name="ROOT"      nr="1"/>
  <element name="Einwohner" nr="1.1"/>
  <element name="id"        nr="1.1.1"/>
  <element name="name"      nr="1.1.2"/>
  <element name="vorname"   nr="1.1.3"/>
  <element name="strasse"   nr="1.1.4"/>
  <element name="Einwohner" nr="1.2"/>
  <element name="id"        nr="1.2.1"/>
  <element name="name"      nr="1.2.2"/>
  <element name="vorname"   nr="1.2.3"/>
  <element name="strasse"   nr="1.2.4"/>
  <element name="Einwohner" nr="1.3"/>
  <element name="id"        nr="1.3.1"/>
...
</Ergebnis>

Hierarchische Einzelnummerierung mit level="single"

Ein ähnliches Ergebnis erzielen Sie bei der Arbeit mit level='single'.


<xsl:number 
     format="1" 
     count="*" 
     level="single"/>

Der Unterschied liegt darin, dass die Hierarchiestufen nicht mitgeführt werden.


<Ergebnis>
  <element name="ROOT"      nr="1"/>
  <element name="Einwohner" nr="1"/>
  <element name="id"        nr="1"/>
  <element name="name"      nr="2"/>
  <element name="vorname"   nr="3"/>
  <element name="strasse"   nr="4"/>
  <element name="Einwohner" nr="2"/>
  <element name="id"        nr="1"/>
  <element name="name"      nr="2"/>
  <element name="vorname"   nr="3"/>
  <element name="strasse"   nr="4"/>
  <element name="Einwohner" nr="3"/>
...
</Ergebnis>

Korrekturbedarf bei xsl:sort

Ohne weitere Anweisungen bezieht sich xsl:number auf die ursprüngliche Reihenfolge der Elemente in der Input-Sequenz.


 <xsl:template match="/">
  <Ergebnis>
   <xsl:for-each 
        select="/ROOT/Einwohner">
    <xsl:sort 
         select="strasse"/>
    <element name="{name()}">
     <xsl:attribute name="nr">
      <xsl:number/>
     </xsl:attribute>
    </element>
   </xsl:for-each>
  </Ergebnis>
 </xsl:template>

Wird diese jedoch mit beeinflusst, so ergibt sich ein interpretationsbedürftiges Ergebnis.


<Ergebnis>
  <element name="Einwohner" nr="1"/>
  <element name="Einwohner" nr="3"/>
  <element name="Einwohner" nr="4"/>
  <element name="Einwohner" nr="7"/>
  <element name="Einwohner" nr="8"/>
  <element name="Einwohner" nr="2"/>
  <element name="Einwohner" nr="5"/>
  <element name="Einwohner" nr="6"/>
</Ergebnis>

In diesem Fall hilft der Aufruf der position()-Funktion im Attribut value: Dadurch wird die Nummerierung aus der sortierten Reihenfolge wiedergegeben.


<xsl:number value="position()"/>

wg / 10. August 2020



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_number.html