Saturday, July 4, 2009

Saxon, Command Line, C#, and XSL 2.0

I've been using Xalan/Xerces for command line XSL transformations for years, but I've been moving farther away from Java over the years, so I wanted something .NET compatible and I wanted something XSL 2.0 compatible. I finally switched to Saxon.

I normally use the standard XML objects in my ASP.NET apps, but I'll switch to Xalan command line tools when I need the "write" extension. I can do the same with Saxon now.

C:\Program Files\Saxon.NET>bin\Transform SaxonTest.xml SaxonTest.xsl


Here is the C# code to call an XSL transformation using Saxon. This one may seem a little odd because the code doesn't save any file since what I'm doing is splitting a large XML file into multiple small files using <xsl:result-document>.

// Create a Processor instance.
Processor p = new Processor();
// Load the source document.
XdmNode node = p.NewDocumentBuilder().Build(new Uri(file));
// Create a transformer for the stylesheet.
XsltTransformer transformer = p.NewXsltCompiler().Compile(myStream).Load();
// Set the root node of the source document to be the initial context node.
transformer.InitialContextNode = node;
// BaseOutputUri is only necessary for xsl:result-document.
transformer.BaseOutputUri = new Uri(file);
// Create a serializer.
Serializer serializer = new Serializer();
transformer.Run(serializer);


Here is the stylesheet I used to leverage the XSL 2.0 equivalent of xalan:write.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="fo xs fn">

<xsl:output method="xml" indent="yes" encoding="UTF-8" name="xmlFormat"/>

<xsl:template match="text()" />

<xsl:template match="/">
<xsl:for-each select="//node()[@fragment='true']">
<xsl:variable name="filename" select="concat( /gpg-book/@local-id, '/', @local-id, '.xml' )"/>
<xsl:result-document href="{$filename}" format="xmlFormat">
<pcu-gpg-book>
<xsl:copy-of select="/gpg-book/taxonomy_pcu"/>
<xsl:copy-of select="/gpg-book/content-metadata"/>
<xsl:copy-of select="/gpg-book/print-pub-metadata"/>
<xsl:copy-of select="parent::node()"/>
</pcu-gpg-book>
</xsl:result-document>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

2 comments:

Byomokesh said...

I am facing same situation. Have you got any solution please tell. I am not getting any output using xsl:result document.

Mattio Valentino said...

Have you tried running the transformation through the command line? That's usually the first thing I do to test out my XSL, where most of my errors occur.

If your trouble is with the XSL, there's a great email list at http://www.mulberrytech.com/xsl/xsl-list/.