Extending XSLT
One thing that I never seem to remember is how to extend my XSLT with extensions. How to include your own namespace and let the transformation engine call my own methods written in C#. It might be hard to remember because I do it once every year, at the most. Now I will write down the procedure here, so that when I google this a year from now, I will find my own blog post. ;) First, write a class that you want to use in your XSLT. Keep the class public and your methods also.
My extension above will return a parameter from the current HttpContext. Some would argue that this should be included in the XSLT 2.0 basic functions, but the transformation does not really have any scope in which it is transformed. Could be a web scenario like mine, or a console application where HttpContext would not be present. Now, in your tranformation code you will have to include this extension class as an argument.
XsltArgumentList arguments = new XsltArgumentList(); arguments.AddExtensionObject("urn:mint", new XsltExtensions());
transformer.Load(XmlReader.Create(stylesheetStream), settings, null); transformer.Transform(XmlReader.Create(documentStream), arguments, output);
The magic happens in row 4 and 5. Now it is possible to call this function from within the XSL stylesheet like this.
<xsl:output method="xhtml" encoding="utf-8" indent="yes" media-type="application/xhtml+xml" /> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="//title" /> </title> </head> <body> <h1>Value of parameter test is: <xsl:value-of select="mint:parameter('test')" /></h1> </body> </html> </xsl:template> </xsl:stylesheet>
Since XSLT is of a very dynamic nature and easy to change, it would seem quite stupid to lock yourself in using only a specified set of extensions. Right? You can solve this by actually loading your XSLT extensions through dependency injection. Let your extension classes implement the following interface.
Now you can add extensions as you will in the configuration of your dependency injection framework. I've chosen to use Unity for my needs, and my implementation looks something like this.
// Add all implementations as extensions to the transformation
foreach (IXsltExtensions extensionObject in extensions)
arguments.AddExtensionObject(extensionObject.NamespaceUri, extensionObject);
}
There you have it! ContainerFactory is in my case a singleton that derives from UnityContainer. Let's hope this will be of any use to you, me or anyone else in a near future.