XSLT/XPath: arithmetische Operationen mit einer Leersequenz


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.

  1. Bisher keine Kommentare.
(wird nicht veröffentlicht)

Time limit is exhausted. Please reload CAPTCHA.