When doing some numerical calculations in XSL templates I stumbled over the fact that a value of 3.600.000.000 which represents the number of microseconds in an hour can be represented in MSXML v6 when running as a 32-bit application, but not when running as a 64-bit application.
What is the biggest number which can be represented by XSLT in 32-bit, and in 64-bit mode? Why is it different?
For reference the XSL template I used for testing was:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="hours" select="1.0"/>
<xsl:variable name="minutes" select="number(60.0 * $hours)"/>
<xsl:variable name="seconds" select="number(60.0 * $minutes)"/>
<xsl:variable name="milliseconds" select="number(1000.0 * $seconds)"/>
<xsl:variable name="microseconds" select="number(1000.0 * $milliseconds)"/>
<xsl:template match="/">
<output>
<value>
<xsl:value-of select="round($microseconds)"/>
</value>
</output>
</xsl:template>
</xsl:stylesheet>
Delphi function to perform XSL transformation:
function TransformMsXmlDocument( XmlDoc, XslDoc: iXmlDomDocument2 ) : UnicodeString;
var
XslDoc2 : iXmlDomDocument2;
XslTemplate : iXslTemplate;
XslProcessor : iXslProcessor;
begin
XslDoc2 := CoFreeThreadedDomDocument60.Create();
XslDoc2.Async := FALSE;
XslDoc2.SetProperty('AllowDocumentFunction', TRUE);
XslDoc2.Load(XslDoc);
XslTemplate := CoXslTemplate60.Create();
XslTemplate.Stylesheet := XslDoc2;
XslProcessor := XslTemplate.CreateProcessor();
XslProcessor.Input := XmlDoc;
XslProcessor.Transform();
Result := XslProcessor.Output;
end;
When performing the transformation within a 32-bit application the generated output is:
<?xml version="1.0"?> <output> <value>3600000000</value> </output>
When performing the transformation within a 64-bit application an exception is thrown:
OLE error C0000090
As pointed out by Martin Honnen in the comment section, XSL Transformation uses the expression language defined by XPath. In XPath 1.0 numbers are defined to use the double-precision 64-bit IEEE 754 number type. The largest decimal number is 1.7976931348623157e+308 with about 15 significant digits, see en.wikipedia.org/wiki/Double-precision_floating-point_format.
The different output between running MSXML in 32-bit and 64-bit mode can be caused by subtle differences in how floating point exceptions are handled by default in Delphi compared to C compilers. In Delphi before version 12 "Athens" some float operations (like division by zero) do trigger an exception by default, while in C they do not. For compatibility with MSXML libraries float exceptions should be disabled using SetExceptionMask on application startup (Note: calling this function is not thread-safe).