Implementing extension methods to XSLT in .Net

Most XSLT processors contain methods to call custom methods (known as extension methods) written in your favourite programming language. Java XSLT processors allow you to write them in Java, and the old MSXML processor allowed you to write the in VBScript or Javascript.

The new .Net Framework classes XslTransform (or more recently XslCompiledTransform) allows you to write them in any .Net language.

But how do you implement these? Well there are two methods you can choose from, read more below the break:

For these examples I will transform a section of XML which contains an element which has got escaped markup. We want to convert this escaped markup into actual elements in the output.

Input file:

 <?xml version="1.0" encoding="utf-8" ?>
<root>
<child>
&<element att="value"&>text here&</element&>
</child>
</root>

Expected Output:

<?xml version="1.0" encoding="utf-8"?>
<root>
<child>
<element att="value">text here</element>
</child>
</root>

<Msxml:Script> Declaration

The first is to embed the method in a mxsl:script element in the XSLT file. You must define the “msxml” namespace, as well as a custom namespace for your code to go into (in this instance “http://www.wackylabs.net/dotnet”).

Then, inside a msxml:script element you can write your C# (or VB.Net) code.

The following is the complete stylesheet showing this approach.

<?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:my="http://www.wackylabs.net/dotnet"
exclude-result-prefixes="my msxsl">
<xsl:output indent="yes" />
<msxsl:script implements-prefix='my' language='C#'>
<![CDATA[
public XPathNavigator ParseXml(string xml)
{
System.IO.StringReader sr = new System.IO.StringReader(xml);
XPathDocument doc = new XPathDocument(sr);
return doc.CreateNavigator();
}
]]>
</msxsl:script>
<xsl:template match="/">
<root>
<child>
<xsl:copy-of select="my:ParseXml(string(.))" />
</child>
</root>
</xsl:template>
</xsl:stylesheet>

The benefits of this is that the entire transformation is defined in one place, and you can transfer the stylesheet between programs without having any other dependencies.

Problems with this approach?

Obviously there is the problem of reuse, but this can be got around using importing of stylesheets. Secondly there is the problem that you don’t get any support from Visual Studio, there is no intellisense, code highlighting or compiler checks.

XsltArgumentList

An alternative is to pass an object which implements your extension methods in as a extension object to the transformation.

Your XSLT looks a lot simpler, as you have got rid of the msxml namespace and script element.

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://www.wackylabs.net/dotnet" exclude-result-prefixes="my">
<xsl:output indent="yes" />
<xsl:template match="child">
<element>
<xsl:copy-of select="my:ParseXml(string(.))" />
</element>
</xsl:template>
</xsl:stylesheet>

You then need to define a class to implement your code:

public class ExtensionMethods
{
public XPathNavigator ParseXml(string xml)
{
System.IO.StringReader sr = new System.IO.StringReader(xml);
XPathDocument doc = new XPathDocument(sr);
return doc.CreateNavigator();
}
}

And finally you need to add an instance of the object to the argument list.

XsltArgumentList args = new XsltArgumentList();
args.AddExtensionObject("http://www.wackylabs.net/dotnet", new ExtensionMethods());

Conclusion

I hope that has given you some help in integrating your .Net code into a XSLT stylesheet.

Leave a Reply