I have been speaking of XSL in my latest articles, so to conclude (for now) the serie, let's see how we can call a C# (or VB.NET) function inside of an XSL file.
Let's first remember two things
-
you should be able to do whatever you want in XSL. However, as this is a functional language, you may need to forget all what you have learned with your favorites programming languages to suceed to do what you want. For examples, the fact that XSL do not allow to update the content of a variable may render things a bit trickier if you are not used to. Calling a C# function should not necessarily be used as soon as you have a problem
-
Visual Studio.NET allows you to debug an XSL file. This is very practical to validate the transformation you do. However, as soon you will call C# code from the XSL file, this won't be possible anymore. Just think before doing it ! (well... you will be able to debug, but no longer in the XSL editor)
However, despite of these two warnings, you can imagine many scenarii when this will be usefull, starting by code factorisation for example : having a single display or rendering function for C# and XSL is of course of great interest !
So let's imagine you have an XML file like this:
<?xml version="1.0" encoding="utf-8" ?>
<Employees>
<Employee>
<FirstName>Pierre-Emmanuel</FirstName>
<LastName>Dautreppe</LastName>
</Employee>
</Employees>
And that you already have your formatting function in C# like (of course, this is a very basic example you could very easily do in XSL)
public class MyXslExtension
{
public string FormatName(string firstName,
string name)
{
return name + ", " + firstName;
}
}
It's almost finished. Now you just need to use this method in an XSL file. Let's write a very basic one
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myUtils="pda:MyUtils">
<xsl:template match="/Employees">
<Employees>
<xsl:for-each select="Employee">
<Employee>
<xsl:value-of select="myUtils:FormatName(FirstName,
LastName)" />
</Employee>
</xsl:for-each>
</Employees>
</xsl:template>
</xsl:stylesheet>
As you can see we have added a new namespace in our file. What is the goal ? To map a function namespace we use in the XSL code to a .NET object we will provide. Note that the function name we use corresponds exactly to the .NET function name we have declared in our object. Note that the value of the namepsace can be whatever you want and will be used later on to do the mapping.
How to use it now ? Let's see the transformation code:
string xslPath = "XSLTFile1.xslt";
string xmlPath = "XMLFile1.xml";
string outputPath = "output.xml";
XsltArgumentList arguments = new XsltArgumentList();
arguments.AddExtensionObject("pda:MyUtils", new MyXslExtension());
using ( StreamWriter writer = new StreamWriter(outputPath) )
{
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(xslPath);
transform.Transform(xmlPath, arguments, writer);
}
And here it is ! When launching your code, .NET will automatically map your object to the namespace used in your XSL file.