XPath 3.0, XPath 2.0, XPath 1.0 / XPath-Funktionen / XPath 3.1: Array

XPath 3.1: Array

XPath 3.1: Array

➪ Ein Array ist ein neuer Datentyp in XDM 3.1.

Auf dieser Seite:

Spezialfunktionen wie array:size, array:get, array:append, array:subarray, array:remove, array:insert-before, array:head, array:tail, array:reverse, array:for-each, array:for-each-pair, array:join, array:filter, array:sort sowie der Einsatz anonymer Funktionen bieten reichhaltige Unterstützung für flexible Implementierungen. Voraussetzung ist ein , der die jeweiligen Features unterstützt.

Der einzubindende Namespace ist:


xmlns:array="http://www.w3.org/2005/xpath-functions/array"

Ein Array der Größe n ist ein Feld oder eine Tabelle mit n Spalten, die in Schleifen von 1 bis n angesprochen werden können. Ein einfaches Beispiel soll das demonstrieren:


<xsl:variable name="varray" select="['Hugo', 'Lotte', 'Theo']"/>

XPath: array:size

Die XPath-Funktion array:size ermittelt die Größe des Arrays:


<xsl:template match="/">
  <root>   
   <xsl:value-of select="array:size($varray)"/>
  </root>
</xsl:template>

Das Ergebnis dürfte wenig überraschen:


<root>3</root>

Die Größe eines leeren Arrays ...


<xsl:value-of select="array:size([])"/>

ergibt 0:


<root>0</root>

Der folgende Aufruf definiert zwei Arrays, von denen das erste Feld wiederum ein Array darstellt.


<xsl:value-of 
     select="array:size([['Hugo', 'Lotte'], ['Theo']])"/>

Die Größe des Gesamtarrays ist 2:


<root>2</root>

XPath: array:get

Die XPath-Funktion array:get liefert jenen Wert, der an einer bestimmten Indexstelle steht (gezählt wird von 1 an).


<xsl:template match="/">
  <root>   
   <xsl:value-of select="array:get($varray, 2)"/>
  </root>
</xsl:template>

array:get($varray, 2) gibt daher das Resultat "Lotte".


<root>Lotte</root>

Besteht hingegen ein Feld in einem Array selber aus einem Array,


<xsl:template match="/">
  <root>   
   <xsl:value-of 
        select="array:get([['Hugo', 'Lotte'], ['Theo']], 1)"/>
  </root>
</xsl:template>

so ist in diesem Fall das Ergebnis:


<root>Hugo Lotte</root>

Etwas interessanter wird es noch, die Einzelwerte des Arrays auszugeben:


<xsl:template match="/">
  <root>
    <xsl:for-each select="1 to array:size($varray)">
     <xsl:variable name="vpos" select="fn:position()"/>
     <wert nr="{$vpos}">
      <xsl:value-of select="array:get($varray, $vpos)"/>
     </wert>
    </xsl:for-each>
  </root>
</xsl:template>

Und auch hierfür gibt es ein Ergebnis:


<root>
  <wert nr="1">Hugo</wert>
  <wert nr="2">Lotte</wert>
  <wert nr="3">Theo</wert>
</root>

XPath: array:append

Die XPath-Funktion array:append fügt einem bestehenden Array ein weiteres Feld hinzu. Dieses neu geschaffene Array können Sie umgehend u.a. mit array:size und array:get auswerten:


<xsl:variable name="varray2" 
     select="array:append($varray, 'Resi')"/>
<xsl:template match="/">
  <root>
   <size>
    <xsl:value-of select="array:size($varray2)"/>
   </size>
   <get>
    <xsl:value-of select="array:get($varray2, 4)"/>
   </get>
  </root>
</xsl:template>

... und mit der neuen Position 4 erhalten Sie dieses Ergebnis:


<root>
 <size>4</size>
 <get>Resi</get>
</root>

XPath: array:subarray

Die XPath-Funktion array:subarray errechnet ein Teil-Array, das mit der gewünschten Start-Position beginnt und alle restlichen Felder übernimmt. Als optionaler zweiter Parameter kann die Anzahl der Felder angegeben werden, die ab der Startposition einbezogen werden sollen.

Beispiel: Aus dem ursprünglich definierten "varray" mit den Inhalten ['Hugo', 'Lotte', 'Theo'] basteln Sie ein Subarray "vsubarray", das an der zweiten Stelle (also bei 'Lotte') beginnt und bis zum Ende ('Theo') durchzieht.


 <xsl:variable name="vsubarray" select="array:subarray($varray, 2)"/>

Der optionale zweite Parameter, der die Anzahl der gesuchten Felder beschränkt, würde ein Subarray ['Lotte', 'Theo'] auch dann nur auf die beiden begrenzen, wenn das Haupt-Array "varray" noch weitere Einträge hätte.


<xsl:variable 
     name="vsubarray" 
     select="array:subarray($varray, 2, 2)"/>

Im vorliegenden Fall macht das keinen Unterschied, und der Aufruf


<xsl:template match="/">
  <root>
   <get nr="1">
    <xsl:value-of select="array:get($vsubarray, 1)"/>
   </get>
   <get nr="{array:size($vsubarray)}">
    <xsl:value-of 
         select="array:get($vsubarray, 
                           array:size($vsubarray)
                          )"/>
   </get>
  </root>
</xsl:template>

... bringt dieses Ergebnis:


<root>
 <get nr="1">Lotte</get>
 <get nr="2">Theo</get>
</root>

Auch hier ist es sinnvoll, sich die Einzelwerte anzusehen:


<xsl:template match="/">
  <root>
    <xsl:for-each select="1 to array:size($vsubarray)">
     <xsl:variable name="vpos" select="fn:position()"/>
     <wert nr="{$vpos}">
      <xsl:value-of select="array:get($vsubarray, $vpos)"/>
     </wert>
    </xsl:for-each>
  </root>
</xsl:template>

Haben Sie etwas anderes erwartet?


<root>
  <wert nr="1">Lotte</wert>
  <wert nr="2">Theo</wert>
</root>

XPath: array:remove

Die XPath-Funktion array:remove ist in der Lage, aus einem Array jenes Feld zu entfernen, das über den Positions-Parameter bestimmt wird.

Beispiel: Aus dem ursprünglich definierten "varray" mit den Inhalten ['Hugo', 'Lotte', 'Theo'] basteln Sie ein zweites Array "vremoved", das den Index an der zweiten Stelle ('Lotte') löscht.


<xsl:variable name="vremoved" select="array:remove($varray, 2)"/>

Bei der Schleife über das Rest-Array ...


<xsl:template match="/">
  <root>
    <xsl:for-each select="1 to array:size($vremoved)">
     <xsl:variable name="vpos" select="fn:position()"/>
     <wert nr="{$vpos}">
      <xsl:value-of select="array:get($vremoved, $vpos)"/>
     </wert>
    </xsl:for-each>
  </root>
</xsl:template>

bleiben nur noch Hugo und Theo übrig:


<root>
  <wert nr="1">Hugo</wert>
  <wert nr="2">Theo</wert>
</root>

Durch eine Sequenz von Löschpositionen können Sie auch mehrere Einzelwerte ansprechen, etwa so:


<xsl:variable name="vremoved" 
     select="array:remove($varray, 2 to 3)"/>

... übrig bliebe dann Hugo:


<root>
  <wert nr="1">Hugo</wert>
</root>

... oder durch gezielte Einzelwerte:


<xsl:variable name="vremoved" 
     select="array:remove($varray, (1,3))"/>

Wenn die Felder an der Stelle 1 und 3 gelöscht werden, dann bleibt nur 'Lotte' übrig:


<root><wert nr="1">Lotte</wert></root>

XPath: array:insert-before

Die XPath-Funktion array:insert-before erlaubt, an einer bestimmten Position ein zusätzlichen Wert einzufügen.

Beispiel: In das ursprünglich definierte "varray" mit den Inhalten ['Hugo', 'Lotte', 'Theo'] füge ich an dritter Stelle den Wert "Tanja" ein.


<xsl:variable name="vinserted" 
     select="array:insert-before($varray, 3, 'Tanja')"/>

Der Aufruf mit array:size und array:get ist wie gehabt:


<xsl:template match="/">
  <root>
    <xsl:for-each select="1 to array:size($vinserted)">
     <xsl:variable name="vpos" select="fn:position()"/>
     <wert nr="{$vpos}">
      <xsl:value-of select="array:get($vinserted, $vpos)"/>
     </wert>
    </xsl:for-each>
  </root>
</xsl:template>

... und bringt ein nachvollziehbares Ergebnis:


<root>
  <wert nr="1">Hugo</wert>
  <wert nr="2">Lotte</wert>
  <wert nr="3">Tanja</wert>
  <wert nr="4">Theo</wert>
</root>

XPath: array:head

Die XPath-Funktion array:head gibt das erste Item des Arrays zurück:


<xsl:template match="/">
  <root>
   <head>
    <xsl:value-of select="array:head($varray)"/>
   </head>
  </root>
</xsl:template>

Und damit sehen Sie auch den Inhalt dieses Items:


<root><head>Hugo</head></root>

XPath: array:tail

Die XPath-Funktion array:tail gibt ab dem zweiten Item (also ohne das erste Item, das über array:head erreicht werden kann) alle Folge-Items zurück.


<xsl:variable name="vtail" select="array:tail($varray)"/>

Der Loop über diese Folge-Items ...


<xsl:template match="/">
  <root>
    <xsl:for-each select="1 to array:size($vtail)">
     <xsl:variable name="vpos" select="fn:position()"/>
     <wert nr="{$vpos}">
      <xsl:value-of select="array:get($vtail, $vpos)"/>
     </wert>
    </xsl:for-each>
  </root>
</xsl:template>

bringt daher dieses Ergebnis:


<root>
  <wert nr="1">Lotte</wert>
  <wert nr="2">Theo</wert>
</root>

XPath: array:reverse

Die XPath-Funktion array:reverse gibt ein Array zurück, dessen Items in umgekehrter Reihenfolge angeordnet sind.

Beispiel: Das ursprünglich definierte "varray" mit den Inhalten ['Hugo', 'Lotte', 'Theo'] wird in der Reihenfolge ['Theo', 'Lotte', 'Hugo'] ausgewertet:


 <xsl:variable name="vreverse" select="array:reverse($varray)"/>
<xsl:template match="/">
  <root>   
    <xsl:for-each select="1 to array:size($vreverse)">
     <xsl:variable name="vpos" select="fn:position()"/>
     <wert nr="{$vpos}">
      <xsl:value-of select="array:get($vreverse, $vpos)"/>
     </wert>
    </xsl:for-each>
  </root>
</xsl:template>

Ich denke, dazu muss ich nicht mehr viel erklären:


<root>
  <wert nr="1">Theo</wert>
  <wert nr="2">Lotte</wert>
  <wert nr="3">Hugo</wert>
</root>

XPath: array:join

Die XPath-Funktion array:join verkettet den Inhalt diverser Arrays in ein einziges Array.

Die Variable "vjoin" macht genau dieses: Sie verkettet drei Arrays in eines. Die Einzelarrays bestehen aus:


<xsl:variable name="vjoin" 
     select="array:join((['Hugo', 'Lotte'], 
                         ['Theo', 'Tanja'], 
                         ['Maxi']))"/>

Der abermalige Aufruf mit array:size und array:get ...


<xsl:template match="/"> 
  <root>   
    <xsl:for-each select="1 to array:size($vjoin)">
     <xsl:variable name="vpos" select="fn:position()"/>
     <wert nr="{$vpos}">
      <xsl:value-of select="array:get($vjoin, $vpos)"/>
     </wert>
    </xsl:for-each>
  </root>
</xsl:template>

... bringt dieses Resultat ans Licht:


<root>
  <wert nr="1">Hugo</wert>
  <wert nr="2">Lotte</wert>
  <wert nr="3">Theo</wert>
  <wert nr="4">Tanja</wert>
  <wert nr="5">Maxi</wert>
</root>

XPath: array:for-each

Die XPath-Funktion array:for-each ermöglicht den flexiblen Einsatz anonymer Funktionen, um Arrays zu modifizieren.

Die Variable "vforeach" nimmt das ursprünglich definierte "varray" mit den Inhalten ['Hugo', 'Lotte', 'Theo'] unter die Lupe. Wenn der jeweilige Einzelwert $v einem Pattern 'Lotte' entspricht, dann soll der Inhalt mit fn:upper-case in Großbuchstaben verwandelt werden, sonst mit fn:lower-case in Kleinbuchstaben.


<xsl:variable name="vforeach" 
     select="array:for-each($varray, 
             function($v){ if (fn:matches($v, 'Lotte') ) 
                           then ( fn:upper-case($v) ) 
                           else ( fn:lower-case($v) ) })"/>

Der Aufruf von "vforeach" erfolgt wie gehabt:


<xsl:template match="/"> 
  <root>   
    <xsl:for-each select="1 to array:size($vforeach)">
     <xsl:variable name="vpos" select="fn:position()"/>
     <wert nr="{$vpos}">
      <xsl:value-of select="array:get($vforeach, $vpos)"/>
     </wert>
    </xsl:for-each>
  </root>
</xsl:template>

... und ruft dieses Resultat hervor:


<root>
  <wert nr="1">hugo</wert>
  <wert nr="2">LOTTE</wert>
  <wert nr="3">theo</wert>
</root>

XPath: Array generieren

Ach ja, wie können Sie ein XPath-Array überhaupt automatisch generieren? Nun, recht einfach:


<xsl:variable name="vgenerated" 
     select="array{ (1 to 3), (4 to 6), (7 to 9)}"/>

Der bereits bekannte Aufruf zaubert daraus:


<root>
  <wert nr="1">1</wert>
  <wert nr="2">2</wert>
  <wert nr="3">3</wert>
  <wert nr="4">4</wert>
  <wert nr="5">5</wert>
  <wert nr="6">6</wert>
  <wert nr="7">7</wert>
  <wert nr="8">8</wert>
  <wert nr="9">9</wert>
</root>

In Verbindung mit dem soeben beschriebenen array:for-each kann das Ganze dann so aussehen:


<xsl:variable name="vforeach2" 
     select="array:for-each(
               array{ 'Hugo', 'Lotte', (1 to 9), 'Theo' }, 
               function($v){ if ($v instance of xs:integer  ) 
                             then ( $v ) 
                             else () })"/>

Der Aufruf ergibt dann ein Ergebnis, das alle ursprünglichen Felder zwar anspricht, die Werte in bestimmten Feldern aber leer sind.


<root>
  <wert nr="1"/>
  <wert nr="2"/>
  <wert nr="3">1</wert>
  <wert nr="4">2</wert>
  <wert nr="5">3</wert>
  <wert nr="6">4</wert>
  <wert nr="7">5</wert>
  <wert nr="8">6</wert>
  <wert nr="9">7</wert>
  <wert nr="10">8</wert>
  <wert nr="11">9</wert>
  <wert nr="12"/>
</root>

XPath: array:filter

Die XPath-Funktion array:filter generiert ein Array mit allen Einträgen, für die die Funktion true() zurückgibt.

Das bereits erwähnte Array besteht aus einzelnen Zeichenketten sowie aus Zahlen. Die Funktion prüft, ob der jeweilige Wert einem regulären Ausdruck entspricht.


<xsl:variable name="vfilter" 
     select="array:filter(
             array{ 'Hugo', 'Lotte', (1 to 9), 'Theo' }, 
             function($v){ fn:matches(
                    xs:string($v), '[A-Z]{1}[a-z]{1,10}') })"/>

Das ist wieder einmal nur bei 'Hugo', 'Lotte' und 'Theo' der Fall.


<root>
  <wert nr="1">Hugo</wert>
  <wert nr="2">Lotte</wert>
  <wert nr="3">Theo</wert>
</root>

XPath: array:for-each-pair

Die XPath-Funktion array:for-each-pair gibt ein Array zurück, das seine Einzelwerte aus jedem Member-Paar an derselben Position bezieht. Zur Berechnung des Ergebnisses wird eine Funktion definiert.

Im vorliegenden Fall werden die beiden Werte multipliziert.


<xsl:variable name="vforeachpair" 
     select="array:for-each-pair(
             array{ (1 to 3) }, 
             array{ (7 to 9) }, 
             function($p1, $p2){ $p1 * $p2 })"/>

Im Einzelnen kommen folgende Ergebnisse zusammen:

Das Ergebnis liest sich so:


<root>
  <wert nr="1">7</wert>
  <wert nr="2">16</wert>
  <wert nr="3">27</wert>
</root>

XPath: array:sort

Die XPath-Funktion array:sort generiert ein Array, das alle Items des ursprünglichen Arrays beinhaltet, jedoch in sortierter Reihenfolge. Dabei ist es möglich, optional eine Collation sowie (ebenfalls optional) eine Funktion einzubinden.

Das einfachste Beispiel finden Sie hier: Die generierte Reihenfolge 4,5,6,1,2,3,7,8,9 ...


<xsl:variable name="vsorted" 
     select="array:sort( array{ (4 to 6), (1 to 3),  (7 to 9)})"/> 

wird durch array:sort aufsteigend sortiert:


<root>
  <wert nr="1">1</wert>
  <wert nr="2">2</wert>
  <wert nr="3">3</wert>
  <wert nr="4">4</wert>
  <wert nr="5">5</wert>
  <wert nr="6">6</wert>
  <wert nr="7">7</wert>
  <wert nr="8">8</wert>
  <wert nr="9">9</wert>
</root>

Der zusätzliche Einsatz einer Collation sorgt dafür, dass beispielsweise bestimmte Sonderzeichen wie "ß" gleichwertig mit "ss" behandelt werden. Eine solche Collation ist die Zeichenkette 'http://www.w3.org/2013/collation/UCA?lang=de;strength=primary', die als zusätzlicher Parameter übergeben wird (anstelle von "(: Collation-Zeichenkette :)").


<xsl:variable 
     name="vsorted2" 
     select="array:sort(
             ['Straße2', 
              'Strasse1', 
              'Weg', 
              'Straße1', 
              'Strasse2', 
              'Pfad'], 
             (: Collation-Zeichenkette :)
             )"/>

Das Sortierungsergebnis ohne Verwendung der Collation hat diesen Aufbau:


<root>
  <wert nr="1">Pfad</wert>
  <wert nr="2">Strasse1</wert>
  <wert nr="3">Strasse2</wert>
  <wert nr="4">Straße1</wert>
  <wert nr="5">Straße2</wert>
  <wert nr="6">Weg</wert>
</root>

Das Sortierungsergebnis mit Verwendung der Collation bietet ein anderes Resultat:


<root>
  <wert nr="1">Pfad</wert>
  <wert nr="2">Strasse1</wert>
  <wert nr="3">Straße1</wert>
  <wert nr="4">Straße2</wert>
  <wert nr="5">Strasse2</wert>
  <wert nr="6">Weg</wert>
</root>

wg / 13. April 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/xpath_array.html