When .NET 2.0 was introduced, quite a long time ago, the whole System.Xml namespace was re-written, due to the poor performance of the System.Xml implementation. Despite the fact that the CLR 2.0 has been around for a few years there are still implementations using CLR 1.x and especially the XSL transformation bits, since that part is completely re-written and marked as obsolete.

But note that they are only being marked as obsolete! You can still compile and run most of the code with just a compiler warning. The old .NET 1.1 classes are still in the CLR 2.0, so you can convert your XSL transformations piece by piece and start using .NET 2.0 or even .NET 3.5 since it is based on .CLR 2.0 (read this post by Scott Hanselman to get a better understanding).

Just make sure that you test everything really thoroughly before putting it in production, since it is not supported.

I am currently moving one of our large applications to .NET 3.5, which has been working really smooth using .NET 1.1, but now I want to use Visual Studio 2008 and C# 3.0 in the upcoming versions. We will eventually upgrade the XSL transformation parts to use the XslCompiledTransform class, but until then we have to stick with the .NET 1.1 classes.

I have stumbled upon a few weird things that stopped working after making the upgrade, not all XSL transformations work out fine. The XSLT not() function stopped working in several XSLT files. This is due to that Microsoft has re-written even these old obsolete classes, not just moved them to a new namespace.

For example I have this XSL snippet, which works fine under a .NET 1.1 compiled environment, which I use to mark alternating lines in different colors.

xsl:if test="not(position() mod 2)">...

In .NET 2.0+ I get an System.InvalidCastException when transforming the XSLT, using the old XSLT transformation classes.

A quick look using the Reflector tool shows us that they have changed the Not function in the BooleanFunctions class (MS.Internal.Xml.XPath.BooleanFunctions in .NET 2.0 and System.Xml.XPath.BooleanFunctions in .NET 1.1). The .NET 1.1 converts the result of the inner expression using the safe Convert.ToBoolean while the .NET 2.0 implementation uses an explicit cast (bool) to convert the result.

The result of the mod operation is a double according to the MS.Internal.Xml.XPath.NumericExpr.GetValue method in .NET 2.0 and System.Xml.XPath.NumericExpr.getValue in .NET 1.1. Both of them are implicitly casted to objects before casted to booleans.

// .NET 2.0 not() implementation
!((bool) query);

// .NET 1.1 not() implementation
!Convert.ToBoolean(query);

The same is for all numeric operations (plus, minus, multiplication, division, modulus and negate) inside the not() XSLT function.

I guess we can’t expect a fix for this, even if it would be welcome. But now you know it!

The problem above was solved with this expression instead:

xsl:if test="(position() mod 2) = 0">

P.S. To get rid of the compiler warnings, insert these pragma directives in your C# code:

#pragma warning disable 0618 // Disable warning CS0618 from here
// your code goes here
#pragma warning restore 0618