Wednesday, 27 May 2009

Saxon XSLT 2.0 format-number problem (update!)


Later: following the post below, I managed to ask on the saxon-help list about this. The reply from Michael Kay (He Should Know!)
is that this is the expected behaviour. Looking in the W3C recommendation, it refers to the JDK 1.1 DecimalFormat class, which indeed states:
Symbol Meaning  
0      a digit  
#      a digit, zero shows as absent  
.      placeholder for decimal separator  
,      placeholder for grouping separator.  
;      separates formats.  
-      default negative prefix.  
%      multiply by 100 and show as percentage  
? multiply by 1000 and show as per mille  
¤ currency sign; replaced by currency symbol; if
         doubled, replaced by international currency symbol.
         If present in a pattern, the monetary decimal separator
         is used instead of the decimal separator.  
X      any other characters can be used in the prefix or suffix  
'      used to quote special characters in a prefix or suffix.  
...so , perverse as it seems, the behaviour is as advertised.

Original post:
One of the (many) advantages of using XSLT 2.0 is its supposed ability to understand scientific notation, e.g. 1E-2 is correctly interpreted as 0.01. However the only implementation I know of for XSLT 2.0 is Saxon, so the XSLT 2.0 standard basically defines this one application. Here's a nasty I discovered while trying to format exponential numbers using Saxon 9.1.0.6: Formatting zero with
format-number(xs:double($myNumber),'#.#######')
causes an empty string to be output.
Heres a sample xml:

<numbers>
<test> id="1">1.3</test>
<test> id="2">8E-4</test>
<test> id="3">8E-8</test>
<test> id="4">0.0</test>
<test> id="5">0</test>
</numbers>


and an xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="text"/>
<xsl:template match="numbers">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="test">
<xsl:value-of select="concat('Original: ',text())"/>
Format with #.#####
'
<xsl:value-of select="format-number(xs:double(.), '#.#####')"/>'
Format with #.#########
'
<xsl:value-of select="format-number(xs:double(.), '#.#########')"/>'
</xsl:template>
</xsl:stylesheet>


But the output is not what one would expect:

Original: 1.3
Format with #.#####
'1.3'
Format with #.#########
'1.3'

Original: 8E-4
Format with #.#####
'.0008'
Format with #.#########
'.0008'

Original: 8E-8
Format with #.#####
''
Format with #.#########
'.00000008'

Original: 0.0
Format with #.#####
''
Format with #.#########
''

Original: 0
Format with #.#####
''
Format with #.#########
''



No comments: