6064 Views // 0 Comments // Not Rated

Embedding .NET Code in XSLT StyleSheets

XSLT is a great way to add extensibility to your application. You are basically storing procedural logic in, essentially, a text file. This way, as your app inevitably changes, you can update it without needing to go through a messy redeployment. Whether you are serializing business objects from a SQL FOR XML query or simply touching up some dynamic HTML, XSLT is the way to go for architectures that anticipate a lot change, and require the flexibility to keep up with it.

A recent "Really? .NET does that? Holy crap!" moment I had after having a typical "Damn. I wish .NET did that. Crap." exasperation moment was when I really really really needed some logic in an XSLT I was working with. Of course, I could have gotten around that by either changing a bunch of queries and adding a utility method that would only get called in one place. But if I could have pulled it off in XSLT, it would have been a mush sexier solution.

Well, it turns out that you inject managed code directly into your XSLT files. Here's what it looks like:

Code Listing 1

  1. <?xml version="0" encoding="UTF-8"?>
  2. <xsl:stylesheet version="0" xmlns:xsl="http://www.worg/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:App="http://www.tempuri.org/App">
  3. <msxsl:script implements-prefix="App" language="C#" />
  4. <![CDATA[
  5. public string ToShortDateString(string date)
  6. {
  7. //convert date to mm/dd/yyyy format
  8. DateTime result;
  9. if (DateTime.TryParse(date, out result))
  10. return result.ToShortDateString();
  11. else
  12. throw new FormatException("Not a date!");
  13. }
  14. ]]>
  15. </msxsl:script>
  16. <xsl:template match="ArrayOfTest">
  17. <TABLE>
  18. <xsl:for-each select="Test">
  19. <TR>
  20. <TD>
  21. <xsl:value-of select="App:ToShortDateString(TestDate)" />
  22. </TD>
  23. </TR>
  24. </xsl:for-each>
  25. </TABLE>
  26. </xsl:template>
  27. </xsl:stylesheet>

Instead of going with normal code formatting, (sorry if the spacing is all drunk) I color-coded this snipit using the following designations:

  • Orange text, first of all, and most obviously, is managed code.
  • Red text is more or less anywhere you declare or call code from XSLT.  Think of "App" as the name of static class that contains the methods defined in the CDATA tag.
  • Blue text is XSLT namespace declarations and other markup "goo" that make everything work.
    • The first line is like a using call that allows inline code in your stylesheet.
    • The next namespace declaration is your class.
    • Finally, the script lines and the CDATA are the vehicle in which the inline code drives.  This is just like a <script> tag for inline JavaScript in HTML.

Then, wherever you would use a built-in XSLT method, you use NAME OF CLASS : NAME OF METHOD ( ARGUMENTS ) to call into your code. I haven't gone too far in terms of figuring out which classes in the framework are fair game here, or how to call into other assemblies. I basically only use this method for things like string manipulation or short cuts around clunky XSLT logic. Besides, if you are writing intense methods in XSLT, then you need to ask yourself why you're using XSLT in the first place...

Now there are two other things to know before using this code. The first thing we need is a way to execute your stylesheet. Here's a common method I use in my utility classes:

Code Listing 2

  1. public static string TransformXML(string xml, string xsltFileName)
  2. {
  3. //initialization
  4. XPathDocument doc = new XPathDocument(new XmlTextReader(new StringReader (xml)), XmlSpace.Preserve);
  5. StringWriter sw = new StringWriter();
  6. XslCompiledTransform xslt = new XslCompiledTransform();
  7. //perform transformation with scripts enabled
  8. xslt.Load(xsltFileName, new XsltSettings(true, true), null);
  9. xslt.Transform(doc, null, new XmlTextWriter(sw));
  10. //return xml
  11. return sw.ToString();
  12. }

This is pretty standard stuff: throw your XML into an XPath doc, create am XslCompliedTransform object, pass in the doc along with the path to a stylesheet, and return the resultant XML, with a bunch of XML writers and readers doing the work behind the scenes.

The one "new" thing here is what I've highlighted in purple. This argument for this particular signature of the Load method (of which there are thousands) is an XsltSettings object. The true's enable document functions and enable scripts, respectively. This is a security feature that allows you to explicitly allow code inside of your XSLT stylesheets, in case you don't know where they are coming from. They default to false.

The other thing to know is also on the topic of security. Now that we have managed code inside our stylesheet, it needs to be complied into an assembly before .NET can do anything with it. And like all other XML compilations, .NET will merrily generate assemblies on the fly and drop them wherever it damn well pleases.

The default location for compiled XSLT inline code is the C:\Windows\Temp directory. So unless you change this behavior, make sure that whomever the current user is going to be, they have read access to this directory. Administrators usually have access to this folders, so Win Forms apps should be okay. Normal users usually don't. So if you are in ASP.NET and using Windows Auth, you need to take this into consideration.

That's it! With custom code embedded in your stylesheets, XSLT becomes even more powerful! Have fun!

No Tags

No Files

No Thoughts

Your Thoughts?

You need to login with Twitter to share a Thought on this post.