XPath / XPath-Funktionen / Stringfunktionen / 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>
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.
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>
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)"/>
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
fg h;	i	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.
V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn
☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de