views:

44

answers:

1

For this XSLT:

    <xsl:variable name="source0" select="number(num2)"/>
    <xsl:variable name="source1" select="number(num3)"/>
    s0 plain: <xsl:value-of select="$source0"/>
    s1 plain: <xsl:value-of select="$source1"/>
    test11: <xsl:value-of select="format-number($source0, '#.#')"/>
    test12: <xsl:value-of select="format-number($source0, '#.###############')"/>
    test21: <xsl:value-of select="format-number($source1, '#.#')"/>
    test22: <xsl:value-of select="format-number($source1, '#.###############')"/>

For XML:

<num2>123456.1234</num2>
<num3>1234567.1234</num3>

I get this output (using Saxon 9.2, XSLT 2.0)

    s0 plain: 123456.1234
    s1 plain: 1.2345671234E6
    test11: 123456.1
    test12: 123456.123399999996764
    test21: 1234567.1
    test22: 1234567.123399999924004

First off... I'm curious why does it suddenly switch between standard and scientific notation when it exceeds 6 digits to the left of decimal place? This is my problem, I want to avoid scientific notation. After various other questions, I discover apparently I'm stuck with putting format-number everywhere.

But format-number doesn't appear to work either. In spite of the fact that the output of "s1 plain" proves that the number of significant digits is known to the processor (I understand about converting to double and back can lose precision, but there is the correct number after such a conversion, so...?), there appears to be no way to output that value in standard non-scientific notation. Is there?

+3  A: 

This is my problem, I want to avoid scientific notation. After various other questions, I discover apparently I'm stuck with putting format-number everywhere.

But format-number doesn't appear to work either.

Apparently you are not using the appropriate features of XSLT 2.0/XPath 2.0.

This transformation:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
 <xsl:output method="text"/>

 <xsl:template match="/*">
  <xsl:variable name="vs0" as="xs:decimal"
  select="xs:decimal(num2)"/>

  <xsl:variable name="vs1" as="xs:decimal"
  select="xs:decimal(num3)"/>

    s0 plain: <xsl:value-of select="$vs0"/>
    s1 plain: <xsl:value-of select="$vs1"/>
    test11: <xsl:value-of select="format-number($vs0, '#.#')"/>
    test12: <xsl:value-of select="format-number($vs0, '#.###############')"/>
    test21: <xsl:value-of select="format-number($vs1, '#.#')"/>
    test22: <xsl:value-of select="format-number($vs1, '#.###############')"/>

 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<nums>
    <num2>123456.1234</num2>
    <num3>1234567.1234</num3>
</nums>

Produces exact results:

s0 plain: 123456.1234
s1 plain: 1234567.1234
test11: 123456.1
test12: 123456.1234
test21: 1234567.1
test22: 1234567.1234

Conclusion: When in need of good precision, always try to use the xs:decimal data-type.

Dimitre Novatchev
@Dimitre: +1 good answer! @taotree: this is what I wrote in the other question as "casting" and use "built-in data type constructors"
Alejandro
Actually, you don't need to use format-number at all when using xs:decimal. All you need to do is cast it to xs:decimal and it will be output in decimal (non-scientific) notation always. I did have to check for empty string because number() is forgiving but xs:decimal() is not. if (string-length(normalize-space($value)) > 0) then xs:decimal($value) else number($value)
taotree