Neues aus der Serie »Man lernt nie aus…«: Ist bei arithmetischen Operationen einer der Operanden die empty sequence
, so ist das Ergebnis bei XSLT/XPath 1.0 NaN
(»not a number«), bei XSLT/XPath 2.0 aber die empty sequence
. Dieses Verhalten ist im XPath-Standard unter 3.4 Arithmetic Expressions definiert.
Ich stand vor dem Problem, eine Variable, die entweder eine xs:decimal
-Zahl oder aber auch die Leersequenz enthält, in eine gültige Instanz von xs:decimal
umzuwandeln, d.h. statt der Leersequenz sollte 0 geliefert werden. Es ist gängige Programmiertechnik, eine Leersequenz durch Anhängen eines Leerstrings – z.B. xs:string( ( (), '') )
– in eine gültige Instanz von xs:string
(d.h. einen Leerstring) umzuwandeln. Die analoge Technik – Addieren einer Null zu einer Leersequenz – funktioniert aber wegen des im Standard definierten Verhaltens nicht. Abhilfe schafft bei XSLT 2.0 eine spezielle Funktion:
<xsl:function name="xsb:force-cast-to-integer" as="xs:decimal"> <xsl:param name="input" as="xs:string?"/> <xsl:choose> <xsl:when test="$input castable as xs:decimal"> <xsl:sequence select="xs:decimal($input)"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="0"/> </xsl:otherwise> </xsl:choose> </xsl:function> |
oder kürzer:
<xsl:function name="xsb:force-cast-to-integer" as="xs:decimal"> <xsl:param name="input" as="xs:string?"/> <xsl:sequence select="if ($input castable as xs:decimal) then xs:decimal($input) else 0"/> </xsl:function> |
Außer bei Leerstring und Leersequenz gibt diese Funktion auch bei nicht konvertierbaren Strings (wie z.B. römischen Zahlen) 0
zurück (was bei mir häufig das gewünschte Verhalten ist), aber die Beschränkung auf Leerstring und Leersequenz lässt sich einfach durch Ersetzen von $input castable as xs:decimal
mit normalize-space($input)
erzielen.
Nachtrag:
Thomas Meinicke merkte zum Rechnen mit Leersequenzen an, dass man zuerst mit exists()
oder empty()
prüfen kann, ob eine Sequenz leer ist, um dann den resultierenden Wahrheitswert in xs:decimal
zu casten, etwa so: xs:decimal(exists( () ) )
. Achtung: Dabei wird die Leersequenz zu 0
, während der Leerstring zu 1
wird.
Nachtrag II:
Leersequenzen führen auch bei Vergleichs-Operationen zur Rückgabe einer Leersequenz, siehe im XPath-Standard unter 3.5.1 Value Comparisons. Da Leersequenzen zu false()
evaluiert werden, ergibt beispielsweise () eq ()
immer false()
. Um zu testen, ob eine Leersequenz vorliegt, muss deshalb empty()
oder exist()
verwendet werden.