C#: Getting started with Saxon-HE XSLT transformation

The XslCompiledTransform class of .NET only supports XSLT 1.0 for some annoying reason. I needed support for version 2.0 and for that I found the free Saxon-HE library through NuGet.

Their API documentation is OK I suppose, although I wish the API was more .NET targeted. Also can’t say I’m impressed by their documentation on how to get started using this stuff.

Either way, here are the steps to do a simple XSLT transformation of an XML document.

using Saxon.Api;

var xslt = new FileInfo(@"C:\path\to\stylesheet.xslt");
var input = new FileInfo(@"C:\path\to\data.xml");
var output = new FileInfo(@"C:\path\to\result.xml");

// Compile stylesheet
var processor = new Processor();
var compiler = processor.NewXsltCompiler();
var executable = compiler.Compile(new Uri(xslt.FullName));

// Do transformation to a destination
var destination = new DomDestination();
using(var inputStream = input.OpenRead())
    var transformer = executable.Load();
    transformer.SetInputStream(inputStream, new Uri(input.DirectoryName));

// Save result to a file (or whatever else you wanna do)

Sure are a lot more steps than I feel necessary here, but oh well… that’s how you do it anyways *shrug*

  • Stefan Mitic

    Thanks man, this made my day!

  • I *think* for the line:

    transformer.SetInputStream(input, new Uri(xml.DirectoryName));

    you meant:

    transformer.SetInputStream(input, new Uri(input.DirectoryName));
    • That is most definitely correct! Thanks 😀

    • Sebastian Uecker

      Actually I think it would even be

      transformer.SetInputStream(inputStream, new Uri(input.DirectoryName));
      • That might be correct too actually. Unable to test it, but looks right. Otherwise the intputStream isn’t actually used for anything at all… updating the post. Thanks 🙂

  • And what if want to process and XML using an XSLT that are not on the web or locally on disk, but I have them in strings/stream. What do I need to pass as URI to SetInputStream? Setting null bombs (in an ugly way). Shouldn’t the first parameter be enough to set an input stream?

    • According to their documentation the baseUri parameter is: “The base URI of the principal input document. This is used for example by the document() function if the document contains links to other documents in the form of relative URIs.”

      So I’d say, try with an empty string, a bogus Uri, http://localhost or whatever?

      • Tried setting it to null or to an Uri instance containing localhost or example.com, and all failed. In thr end I wound up writing XSLT input to TEMP file and seyting BaseUri to file path to TEMP folder. That at least worked.

        • Well that’s a bit annoying, but good to hear you found a workaround anyways. Let me know if you find a proper solution though 🙂

  • Alejandro

    Thank you!