XQuery / XPath 3.1: Arrays in XQuery

XPath 3.1: Arrays in XQuery

XPath 3.1: Arrays in XQuery

➪ Auch die erweiteren Funktionen von XPath 3.1, zum Beispiel die Array-Funktionen, stehen in XQuery zur Verfügung. Voraussetzung ist die Einbindung des speziellen Namespaces.

Auf dieser Seite:

declare namespace 
   array = "http://www.w3.org/2005/xpath-functions/array";

Damit ausgerüstet, ist es ein Leichtes, ein zu definieren und auszuwerten. Die Schleife geht von 1 bis zur Array-Größe; über array:get wird der Wert an der jeweiligen Stelle ausgelesen.


<erg> {
    let $vvar := ['Hugo', 'Lotte', 'Theo']
    for $x in 1 to array:size($vvar) return
      <WERT name="{$x}">
        {array:get($vvar, $x)}
      </WERT>
  }</erg>

Das Ergebnis ist dann:


<erg>
   <WERT name="1">Hugo</WERT>
   <WERT name="2">Lotte</WERT>
   <WERT name="3">Theo</WERT>
</erg

array:reverse

Die ursprüngliche Reihenfolge des Arrays können Sie mit array:reverse leicht umkehren.


<erg> {
    let $vvar := ['Hugo', 'Lotte', 'Theo']
    let $vrev := array:reverse($vvar)
    for $x in 1 to array:size($vrev) return
      <WERT name="{$x}">
        {array:get($vrev, $x)}
      </WERT>
  }</erg>

Das Ergebnis ist dann:


<erg>
   <WERT name="1">Theo</WERT>
   <WERT name="2">Lotte</WERT>
   <WERT name="3">Hugo</WERT>
</erg

array:subarray

Auch das Subarray lässt sich definieren: Im folgenden Fall werden aus dem ursprünglichen Array ab dem zweiten Arrayfeld drei weitere Werte entnommen und wie vorher ausgegeben.


<erg> {
    let $vvar := ['Hugo', 'Lotte', 'Theo', 'Alfons', 'Niki']
    let $vsubarray := array:subarray($vvar, 2, 3) 
    for $x in 1 to array:size($vsubarray) return
      <WERT name="{$x}">
        {array:get($vsubarray, $x)}
      </WERT>
  }</erg>

Das Ergebnis ist dann:


<erg>
   <WERT name="1">Lotte</WERT>
   <WERT name="2">Theo</WERT>
   <WERT name="3">Alfons</WERT>
</erg

array:insert-before, array:tail

Während Sie mit array:insert-before in einem Array an einer bestimmten Stelle (hier: vor der 3. Stelle) einen weiteren Wert einfügen können (das Array umfasst nunmehr die Reihenfolge 'Hugo', 'Lotte', 'Tanja', 'Theo'), unterstützt Sie array:tail darin, alle Felder anzusprechen, ausgenommen das erste.


<erg>  {
    let $vvar := ['Hugo', 'Lotte', 'Theo']
    let $vib := array:insert-before($vvar, 3, 'Tanja')
    let $vtail := array:tail($vib)
    for $x in 1 to array:size($vtail)
    where array:get($vtail, $x) != 'Tanja'
    return
      <WERT name="{$x}">
        {array:get($vtail, $x)}
      </WERT>
  }</erg>

Die Ausgabe lautet daher folgerichtig:


<erg>
   <WERT name="1">Lotte</WERT>
   <WERT name="2">Tanja</WERT>
   <WERT name="3">Theo</WERT>
</erg

Leicht erweitert, können Sie nun mit der WHERE-Klausel dafür sorgen, dass 'Tanja' nicht ausgegeben wird.


<erg>  {
    let $vvar := ['Hugo', 'Lotte', 'Theo']
    let $vib := array:insert-before($vvar, 3, 'Tanja')
    let $vtail := array:tail($vib)
    for $x in 1 to array:size($vtail)
    where array:get($vtail, $x) != 'Tanja'
    return
      <WERT name="{$x}">
        {array:get($vtail, $x)}
      </WERT>
  }</erg>

Die Ausgabe lautet daher mit der ursprünglichen Nummerierung ('Tanja' an Platz 2 fehlt):


<erg>
   <WERT name="1">Lotte</WERT>
   <WERT name="3">Theo</WERT>
</erg

array:for-each

Die array:for-each-Funktion durchläuft ihrerseits die Bestandteile des Arrays. Durch eine zusätzliche interne Funktion lässt sich jeder Einzelwert modifizieren.

So prüft der folgende Aufruf, ob der Feldinhalt einem regulären Ausdruck entspricht: Das erste Zeichen muss entweder "T" oder "H", die restlichen Buchstaben klein sein. In diesem Fall wird der gesamte Feldinhalt großgeschrieben, andernfalls ist der Feldinhalt leer.


<erg> {
    let $vvar := ['Hugo', 'Lotte', 'Theo']
    let $vvar2 := array:for-each($vvar, 
       function($v){ 
                     if (fn:matches($v, '^[TH][a-z]+') ) 
                     then ( fn:upper-case($v) ) 
                     else ( ) })
    for $x in 1 to array:size($vvar2) return
      <WERT name="{$x}">
        {array:get($vvar2, $x)}
      </WERT>
  }</erg>

Das Ergebnis lautet daher:


<erg>
   <WERT name="1">HUGO</WERT>
   <WERT name="2"/>
   <WERT name="3">THEO</WERT>
</erg

array:for-each-pair

array:for-each-pair erlaubt, Wertepaare zu bilden und diese durch eine interne Funktion miteinander zu verknüpfen. Im folgenden Beispiel werden die drei Wertepaare (9, 36), (5, 81) und (3, 57) gebildet, wobei in der Funktion (nach Prüfung, ob der Wert auch eine xs:integer-Zahl ist) die jeweils erste Zahl von der zweiten Zahl subtrahiert wird. Damit erhalten Sie folgende Ergebnisse:

36 - 9 27
81 - 5 76
57 - 3 54

<erg>   {
        let $vvar := array:for-each-pair(
             array{ (9, 5, 3) }, 
             array{ (36, 81, 57) }, 
             function($p1 as xs:integer, $p2  as xs:integer)  
                     as xs:integer 
                     { $p2 - $p1})
        for $x in 1 to array:size($vvar)
        return
            <WERT name="{$x}">
                {array:get($vvar, $x)}
            </WERT>
    }</erg>

Das Ergebnis lautet daher:


<erg>
   <WERT name="1">27</WERT>
   <WERT name="2">76</WERT>
   <WERT name="3">54</WERT>
</erg

Und wenn Sie die Summe dieser subtrahierten Wertepaare haben möchten, so steht die altbewährte sum-Funktion gern bereit ...


<erg> {
        let $vvar := array:for-each-pair(
             array{ (9, 5, 3) }, 
             array{ (36, 81, 57) }, 
             function($p1 as xs:integer, $p2  as xs:integer)  
                     as xs:integer 
                     { $p2 - $p1})
        return sum($vvar)        
    }</erg>

... und beglückt Sie mit diesem Resultat:


<erg>157</erg

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/XQuery15.html