Developer

How using an XSL/C# hybrid may prevent an accounting snafu

Check out this hybrid of XSL and C# that Edmond Woychowsky used to resolve a floating point error in Microsoft's implementation of the XPath sum() function.

 

It's been my experience that developers and accountants get along about as well as cats and dogs. And, being a developer, I tend to take the developer's side when there's an argument. But accountants aren't entirely at fault for this feud; from an accountant's point of view, developers play fast and loose with numbers — the lifeblood of the accounting profession.

Consider the XPath sum() function in Microsoft's MSXML, which returns the sum of the numeric value of each node in a node set like the one in Listing A.

Listing A

An example node set

<value>4.42</value>

<value>25.00</value>

<value>0.60</value>

Seems simple enough, doesn't it? The sum for the node set shown in Listing A should be 30.02, right? Would you believe that, depending on the version of MSXML you're using, you could see 30.02 or 30.020000000000003? Maybe the accountants aren't as crazy as we were originally lead to believe.

When I first encountered this problem, I immediately realized that this was a floating point error in Microsoft's implementation of the XPath sum() function. Since I was working in XSL version 1.0, I did the first thing that came to mind: I wrote a workaround JavaScript extension function and proceeded to bask in the light of my own brilliance. Unfortunately, my brilliance was eclipsed by a rare bit of consistency on Microsoft's part — its implementation of JavaScript (Jscript) had the exact same issue.

It was at this low point when I remembered reading that Microsoft allowed for extension functions in languages other than JavaScript. Ruling out VBScript (which would probably produce the same result), I decided to give C# a try. The result of this hybrid of XSL and C# is shown in Listing B.

Listing B

An XSL/C# hybrid

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:cs="urn:cs">

<!— C# extension function used to avoid rounding errors in the sum function —>

<msxsl:script language="CSharp" implements-prefix="cs"><![CDATA[

public string sum(System.Xml.XPath.XPathNodeIterator xni)

{

double sum = 0;

for (int i = 0; i < xni.Count; i++)

{

try

{

xni.MoveNext();

if(xni.Current.Value != "NaN")

sum += double.Parse(xni.Current.Value);

}

catch(Exception ex) { }

}

return sum.ToString();

}

]]></msxsl:script>

<xsl:template match="/">

<xsl:element name="sum">

<xsl:value-of select="//value"/>

</xsl:element>

</xsl:template>

</xsl:stylesheet>

Imagine my surprise when this example of Frankencode worked! Not only did it work, but it also produced the correct results of 30.02.

Shortly after this scenario played out, I became somewhat sympathetic to the plight of accountants. From their point of view, developers rely heavily on Sir Terry Prachett's Third Law. However, since I'm fan of both the works of Sir Terry Prachett and functional programming, I'll use extension functions again in the future. After all, I'm only somewhat sympathetic to the plight of accountants.

Get weekly development tips in your inbox Keep your developer skills sharp by signing up for TechRepublic's free Web Developer newsletter, delivered each Tuesday. Automatically subscribe today!

Editor's Picks

Free Newsletters, In your Inbox