Home
Über mich
Veröffentlichungen

XML XML-Schema XPath XSL-T XSL-FO XQuery XProc SVG

XPath / XPath-Funktionen / Stringfunktionen / XPath: string oder xs:string?

XPath: string oder xs:string?

XPath: string oder xs:string?

➪ Die XPath-Funktion string konvertiert einen Textnode in einen String.

Auf dieser Seite:

Einfach und unkompliziert ist die Anwendung der string-Funktion bei einem einzelnen, klar definierten Element.

Hier wird ein Textnode in einen String konvertiert.


<xsl:value-of select="string(/Mensch/nachname/text())"/>

Dieses Beispiel setzt voraus, dass der XPath-Pfad //Mensch[1]/nachname vorhanden ist; das Ergebnis wäre "Problemlos".


<Mensch>
  <vorname>Peter</vorname>
  <nachname>Problemlos</nachname>
  <beruf/>
</Mensch>

Sehr hilfreich ist die string-Funktion, wenn es darum geht, leere oder gar nicht vorhandene Elemente zu prüfen. Das Element beruf ist in diesem Beispiel leer, das Element hobby gar nicht vorhanden.


<xsl:if test="string(/Mensch/beruf) = ''">
  <xsl:value-of select="/Mensch/vorname"/>
  <xsl:text> </xsl:text>
  <xsl:value-of select="/Mensch/nachname"/>
  <xsl:text> hat keine Berufsbezeichnung angegeben.</xsl:text>
</xsl:if> 
<xsl:if test="string(/Mensch/hobby) = ''">
  <xsl:value-of select="/Mensch/vorname"/>
  <xsl:text> </xsl:text>
  <xsl:value-of select="/Mensch/nachname"/>
  <xsl:text> hat kein Hobby angegeben.</xsl:text>
</xsl:if> 

Vorsicht bei mehreren Childnodes

Eine Ausgabe erhalten Sie auch bei folgendem Aufruf, wo sämtliche Textnodes des komplexen Elements Mensch in einen Einzelstring <s> ... </s> übernommen werden (es entstehen also nicht mehrere <s> ... </s>).


<xsl:for-each 
     select="string(//Ort[1]/Mensch[1])">
  <s><xsl:value-of select="."/></s>
</xsl:for-each>

oder alternativ


string(/Ort[1]/Mensch[1])

In diesem Ansatz wird jenes Element Mensch über XPath adressiert. Wenn das XML-Inputdokument so aussieht:


<Mensch>
   <id>1</id>
   <name>Holzflos</name>
   <vorname>Hugo</vorname>
   <Gehalt>234.56 Euro</Gehalt>
   <idOrt>1</idOrt>
   <Kauf>
    <idMensch>1</idMensch>
    <anzahl>3</anzahl>
    <bez>Hemd</bez>
    <preis>12.99</preis>
    <Gesamt>38.97</Gesamt>
   </Kauf>
   <Kauf>
    <idMensch>1</idMensch>
    <anzahl>9</anzahl>
    <bez>Hose</bez>
    <preis>12.99</preis>
    <Gesamt>116.91</Gesamt>
   </Kauf>
   <Kauf>
    <idMensch>1</idMensch>
    <anzahl>8</anzahl>
    <bez>Schuhe</bez>
    <preis>12.99</preis>
    <Gesamt>103.92</Gesamt>
   </Kauf>
</Mensch>

... dann sähe das Resultat so aus:


1 Holzflos Hugo 234.56 1
1 3 Hemd 12.99 38.97
1 9 Hose 12.99 116.91
1 8 Schuhe 12.99 103.92

Ob Sie mit dem Ergebnis wohl zufrieden sind??

Unzulässig ist dagegen die Übergabe einer Nodelist mit mehreren Items, was zu der Fehlermeldung "A sequence of more than one item ... " führt. Vergleichen Sie auch hier die Sequenz-Funktionen zero-or-one und exactly-one.


<xsl:for-each 
     select="string(//Ort[1]/Mensch[1]/child::*)">
  <s><xsl:value-of select="."/></s>
</xsl:for-each>
Fehlerlevel: fatal
Beschreibung: XPTY0004: A sequence of more than one item is 
not allowed as the first argument of string() (<id/>, <name/>, ...)
URL: http://www.w3.org/TR/xpath20/#ERRXPTY0004

bzw.


<xsl:for-each 
     select="string(//Mensch)">
  <s><xsl:value-of select="."/></s>
</xsl:for-each>
Fehlerlevel: fatal
Beschreibung: XPTY0004: A sequence of more than one item is 
not allowed as the first argument of string() (<Mensch/>, <Mensch/>, ...)
URL: http://www.w3.org/TR/xpath20/#ERRXPTY0004

Siehe auch den Vergleich von leeren Sequenzen mit leeren Strings.

fn:string oder xs:string?

Die string-Funktion wird in XPath 1.0 verwendet; in XPath 2.0 steht zusätzlich der Schema-Datentyp xs:string zur Verfügung (xmlns:xs="http://www.w3.org/2001/XMLSchema). Je nach XPath-Version wird die string-Funktion intern anders verarbeitet.

XPath 1.0 string(object): string. Ist object eine Liste mit mehreren Nodes, muss damit gerechnet werden, dass nur der erste Node verarbeitet wird; die restlichen Nodes werden ignoriert.
XPath 2.0 fn:string() as xs:string; fn:string($arg as item()?) as xs:string

Bei einigen XSLT-3.0-Prozessoren können Sie den Unterschied zwischen xs:string und fn:string gut erkennen, wenn Sie eine leere Sequenz analysieren. Betrachten Sie die Variable "v1", die lediglich ein root-Element aufweist; dieses besitzt jedoch kein Childnode wert, dessen Existenz Sie überprüfen wollen.


<xsl:variable name="v1"><root/></xsl:variable>

<xsl:template match="/">
  <ergebnis>
    <empty>
      <xsl:value-of 
           select="empty($v1/root/wert)"/>
    </empty>
    <empty_xs_string>
      <xsl:value-of 
           select="empty(xs:string($v1/root/wert))"/>
    </empty_xs_string>
    <exists_string>
      <xsl:value-of 
           select="exists(string($v1/root/wert))"/>
    </exists_string>
    <one-or-more_string>
      <xsl:value-of 
           select="one-or-more(string($v1/root/wert))"/>
    </one-or-more_string>
    <exactly-one_string>
        <xsl:value-of 
             select="exactly-one(string($v1/root/wert))"/>
    </exactly-one_string>
  </ergebnis>
</xsl:template>

Die Gegenprobe bestätigt das mit dem jeweiligen Ergebnis "false".


<xsl:template match="/">
  <ergebnis>
    <emptystring>
      <xsl:value-of 
           select="empty(string($v1/root/wert))"/>
    </emptystring>
    <exists>
      <xsl:value-of 
           select="exists($v1/root/wert)"/>
    </exists>
    <exists_xs_string>
      <xsl:value-of 
           select="exists(xs:string($v1/root/wert))"/>
    </exists_xs_string>
    <!--<one-or-more>
    <xsl:value-of 
         select="one-or-more($v1/root/wert)"/>
  </one-or-more>-->
    <!--<one-or-more_xs_string>
    <xsl:value-of 
         select="one-or-more(xs:string($v1/root/wert))"/>
  </one-or-more_xs_string>-->
    <!--<exactly-one>
        <xsl:value-of 
             select="exactly-one($v1/root/wert)"/>
    </exactly-one>-->
    <!--<exactly-one_xs_string>
        <xsl:value-of 
             select="exactly-one(xs:string($v1/root/wert))"/>
    </exactly-one_xs_string>-->
  </ergebnis>
</xsl:template>

Typabhängige Auswertung

In XSLT 2.0 hängt die Auswertung von string() vom Typ des übergebenen Parameters ab. Ist der Input ein Atom-Wert (atomic value), so werden Boolean-Werte (xs:boolean mit true() oder false()) als Strings dargestellt (true, false). Ähnliches gilt für Zahlen oder Datumswerte: Sie können die Inhalte mit Stringfunktionen weiter verarbeiten, aber keine Rechenoperationen durchführen.


<xsl:variable 
     name="v1" 
     select="string(//Ort[1]/Mensch[2]/Kauf[2]/preis)"/>
<xsl:variable 
     name="v2" 
     select="string(//Ort[1]/Mensch[2]/Kauf[2]/anzahl)"/>   

Eine Multiplikation der Stringwerte läuft auf einen Fehler:


<xsl:value-of select="$v2 * $v1"/>
Fehlerlevel: fatal
Beschreibung: XPTY0004: Arithmetic operator is not defined for 
arguments of types (xs:string, xs:string)
URL: http://www.w3.org/TR/xpath20/#ERRXPTY0004

Prinzipiell korrekt wäre nun eine Typkonvertierung von string zu number:


<xsl:value-of 
     select="number($v2) * number($v1)"/>

Hier schlägt jedoch die automatische Typkonvertierung für number() zu, die beide Werte als xs:double betrachtet und entsprechend behandelt. Ist $v2=25.99 und $v1=7, so wird als Ergebnis nicht 181.93 berechnet, sondern 181.92999999999998.

Der scheinbar vernachlässigbare Rundungsfehler kann sich bei sehr zahlreichen Rechenoperationen (Summierungen) zu einem absoluten Fehler auswirken. Daher empfiehlt sich eine Typkonvertierung als xs:decimal:


<xsl:value-of 
     select="xs:decimal($v2) * xs:decimal($v1)"/>

Sonderzeichen

Ein xs:string kann auch Sonderzeichen wie Carriage Return (#xD), Linefeed (#xA) oder Tabulator (#x9) beinhalten.


<erg>
<xsl:variable 
     name="vstring" 
     as="xs:string"> ab;cde&#xA;fg  h;&#x9;i&#x9;jk </xsl:variable>
<xsl:value-of select="$vstring"/>
</erg>

Das Ergebnis des vorstehenden Aufrufs beinhaltet auch den Zeilenumbruch und das Tabulatorzeichen.


<erg>   ab;cde
fg  h;	i	jk    </erg>

Siehe auch normalize-space und tokenize.

wg / 17. Dezember 2019



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