XPath 3.0, XPath 2.0, XPath 1.0 / XPath-Funktionen / Stringfunktionen / XPath: tokenize

XPath: tokenize

XPath: tokenize

➪ Die XPath-Funktion tokenize konvertiert einen String in eine Sequenz.

Auf dieser Seite:

Die tokenize-Funktion ist im Grunde das Gegenstück zu . Während string-join in der Lage ist, eine Sequenz mit mehreren Items in einen Einzelstring zu konvertieren, wobei auch Trennzeichen eingefügt werden können (im Beispiel: ";"), kann tokenize einen derartigen unter Zuhilfenahme des Trennzeichens wieder in eine Sequenz konvertieren.

Um das zu verdeutlichen, generieren Sie zunächst eine Sequenz aus den Werten 'Meier', 'Schulze', 'Müller', 'Schmidt' sowie den Zahlen 1 bis 10.


<xsl:variable name="v1" as="xs:string+">
  <xsl:for-each 
       select="('Meier', 
                'Schulze', 
                'Müller', 
                'Schmidt', 
                1 to 10)">
    <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:variable>

Im nächsten Schritt konvertieren Sie die Sequenz in einen String mit dem Trennzeichen ";".


<xsl:variable name="v2" as="xs:string">
    <xsl:value-of select="string-join($v1, ';')"/>
</xsl:variable>

Denselben Effekt erreichen Sie übrigens auch mit dem separator-Attribut von xsl:value-of:


<xsl:value-of 
     select="'Meier', 
             'Schulze', 
             'Müller', 
             'Schmidt', 
             1 to 10" 
     separator=";"/>

Zur Kontrolle können Sie sich den generierten String anzeigen lassen:


<xsl:value-of select="$v2"/>

Hier ist also der String:


Meier;Schulze;Müller;Schmidt;1;2;3;4;5;6;7;8;9;10

Nun kommt tokenize ins Spiel, das den String in eine Itemlist aufsplittet:


<xsl:for-each 
     select="tokenize(xs:string($v2), ';')">
  <item>
    <xsl:value-of select="."/>
  </item>      
</xsl:for-each>

Resultat:


<item>Meier</item>
<item>Schulze</item>
<item>Müller</item>
<item>Schmidt</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>

Flags

Wie wollen Sie jedoch verfahren, wenn die Zeichentrenner kein Semikolon darstellen, sondern aus Zeichen bestehen, die in Ausdrücken eine besondere Bedeutung haben, etwa "." oder "\"?


Meier.Schulze.Müller.Schmidt.1.2.3.4.5.6.7.8.9.10
Meier\Schulze\Müller\Schmidt\1\2\3\4\5\6\7\8\9\10

Da auch die tokenize-Funktion mit regulären Ausdrücken arbeitet, benötigen Sie den Einsatz eines speziellen Flags q, das dafür sorgt, dass Spezialzeichen in den regulären Ausdrücken als normale Zeichen betrachtet werden. Allgemeines zum Thema Flags finden Sie unter .


<xsl:for-each 
     select="tokenize('Meier\Schulze\Müller\Schmidt', 
                      '\', 
                      'q')">
    <item>
        <xsl:value-of select="."/>
    </item>
</xsl:for-each>

Dieselbe Lösung sieht in XQuery so aus:


xquery version '3.0';
<erg>{
for $m in tokenize('Meier\Schulze\Müller\Schmidt', 
                      '\', 
                      'q') 
       return 
       <item>{$m}</item>
}</erg>

Type-casting

Interessant ist auch die Variante, die einzelnen Items der generierten Sequenz auf bestimmte Eigenschaften hin zu überprüfen, etwa, ob sie sich als xs:integer casten lassen. Damit fallen die Werte 'Meier', 'Schulze', 'Müller', 'Schmidt' aus der Sequenz heraus, übrig bleiben die Integerwerte.


<xsl:for-each 
   select="tokenize(xs:string($v2), ';')
           [. castable as xs:integer]">
  <item>
    <xsl:value-of select="."/>
  </item>      
</xsl:for-each>

Resultat:


<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>

tokenize vs. xs:token

Etwas mißverständlich ist die Namensgebung etwa für xs:token: Hierbei handelt es sich um einen String ohne Whitespaces wie line feeds (#xA), carriage returns (#xD) oder tabs (#x9), die jedoch innerhalb von xs:token ggf. erlaubt sein können.


<xs:restriction base="xs:normalizedString">
 <xs:whiteSpace value="collapse"/>
</xs:restriction>

Ein kann jedoch auch jene Sonderzeichen beinhalten.


<xsl:variable 
     name="vstring" 
     as="xs:string"> ab;cde&#xA;fg  h;&#x9;i&#x9;jk </xsl:variable>
     <erg3>
        <xsl:for-each 
          select="tokenize($vstring, ';')">
          <item>
            <xsl:value-of select="."/>
          </item>   
        </xsl:for-each>
     </erg3>

Nun könnten Sie erwarten, dass die tokenize-Funktion sich weigert, einen solchen String abzuarbeiten. Fehlanzeige:


   <erg3>
      <item>   ab</item>
      <item>cde
fg  h</item>
      <item>	i	jk    </item>
   </erg3>

Erst die kombinierte Anwendung von löscht die unerwünschten Sonderzeichen, sodass die tokenize-Funktion zu einem anderen Resultat kommt.


<erg4>
  <xsl:for-each 
    select="tokenize(normalize-space($vstring), ';')">
    <item>
      <xsl:value-of select="."/>
    </item>   
  </xsl:for-each>
</erg4>

Noch besser (Danke für den Tipp!): Deklarieren Sie die Variable gleich mit dem passenden Datentyp xs:token.


<xsl:variable
    name="vtoken"
    as="xs:token"> ab;cde&#xA;fg  h;&#x9;i&#x9;jk </xsl:variable>
<erg4>
    <xsl:for-each select="tokenize($vtoken, ';')">
        <item>
            <xsl:value-of select="."/>
        </item>
    </xsl:for-each>
</erg4> 

In XQuery gefällt mir dieser Ansatz genau so gut:


xquery version '3.0';
<erg4>{
let $v as xs:token := " ab;cde&#xA;fg h;&#x9;i&#x9;jk "
for $m in tokenize($v, ';') return 
<item>{$m}</item>
}</erg4>

Das Ergebnis:


<erg4>
   <item>ab</item>
   <item>cde fg h</item>
   <item> i jk</item>
</erg4>

wg / 4. Oktober 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/tokenize.html