I think you are referring to Saxon 9.x when running in backwards compatibility mode, i.e. with version="1.0".
Saxon's behaviour is correct according to the spec. The fact that number-to-string conversion gives different results in XSLT 2.0 in backwards compatibility mode from the results produced by an XSLT 1.0 processor is a known documented incompatibility: see the compatibility appendix of the XPath 2.0 specification, including the published errata.


Michael Kay

From: Karthick Sankarachary [mailto:karthick.sankarachary@gmail.com]
Sent: 11 September 2009 01:52
To: Mailing list for the SAXON XSLT and XQuery processor
Subject: [saxon] Casting to strings in XSLT 1.0


It appears that there might be a bug in the way the XSLT 1.0 parser converts numbers into strings.

Considering that XSLT 1.0 relies on XPath 1.0 functions, you would expect a non-integer number to be converted into a decimal form, as described in the XPath 1.0 string function section. However, when given a number greater than or equal to a million, XSLT 1.0 converts it to a floating point, which goes against its spec. While this behavior is correct for XSLT 2.0, which relies on XPath 2.0 casting rules, it is not expected in XSLT 1.0, IMHO.

For your convenience, please find down below a test case that exhibits this problem.

First though, let us show you the output that we expect to see:

<Number xsi:schemaLocation="http://www.example.org/Number Number.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">1000000</Number>

Next, the actual output of the transformation, as performed by Saxon's XSLT 1.0:

<n:Number xmlns:n="http://www.example.org/Number" xmlns="http://www.example.org/Number"
          xsi:schemaLocation="http://www.example.org/Number Number.xsd">1.0E6</n:Number>

Finally, the JUnit test case:

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.io.Writer;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import junit.framework.TestCase;

import org.junit.Test;

public class NumberTestCase extends TestCase {
     public static final String INPUT_NUMBER = "1000000";
    @Test public void testXsl() throws Exception {           
        TransformerFactory tfactory = TransformerFactory.newInstance();

        String source = "<?xml version='1.0' encoding='UTF-8'?><n:Number xmlns:n='http://www.example.org/Number'>" + INPUT_NUMBER + "</n:Number>";
        String xsl = "<?xml version='1.0' encoding='UTF-8'?><xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:n='http://www.example.org/Number' xmlns:xs='http://www.w3.org/2001/XMLSchema' exclude-result-prefixes='xs xsi xsl' xmlns='http://www.example.org/Number'>    <xsl:namespace-alias stylesheet-prefix='n' result-prefix='#default'/>    <xsl:output method='xml' encoding='UTF-8' indent='yes'/>    <xsl:template match='/'>        <n:Number>            <xsl:attribute name='xsi:schemaLocation'>                <xsl:value-of select=\"'http://www.example.org/Number Number.xsd'\"/>            </xsl:attribute>            <xsl:variable name='var1_instance' select='.'/>            <xsl:for-each select='$var1_instance/n:Number'>                <xsl:value-of select='number()'/>            </xsl:for-each>        </n:Number>    </xsl:template></xsl:stylesheet>";
        Transformer transformer =
            tfactory.newTransformer(new StreamSource(new ByteArrayInputStream(xsl.getBytes())));
        Writer writer = new StringWriter();
        transformer.transform(new StreamSource(new ByteArrayInputStream(source.getBytes())),
                              new StreamResult(writer));

        System.out.println("The result of the transformation is shown below:\n" + writer.toString());
        assertTrue("The result does not contain the expected number", writer.toString().contains(INPUT_NUMBER));      


Best Regards,
Karthick Sankarachary