Friday 24 June 2011

C#/XSLT - Adding custom xml namespaces / extension objects


Today I had a bit of a ball ache trying to capture errors that were failing within my XSLT. Whenever I called the document() function with an invalid file path, the document will fail to transform and nothing will be displayed.

Initially I looked at trying to capture the error using when/otherwise by passing the result of the document() function into a test attribute. This simply does not work, even if you convert the result to a boolean. So after wading through crappy advice, I thought as I'm using C# to do my transformations, I will simply add a custom namespace.

The following example explains how to check if a file exists using a custom namespace in C#.


1. Add a custom xmlns reference to your XSL file. The format is as follows: xmlns:<tag name>="<namespace>"

Example:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:file="urn:schemas-file">


This will allow me to prefix functions within my urn:schemas-file namespace with the prefix: file



2. Now the XSL has access to this custom library of functions (which we haven't yet coded yet)... we need to actually call one of our functions within the XSL.

Example:
<!-- Sample variable holding a location to a file -->
<xsl:variable name="filePath" select="../root/xml/testdocument.xml" />
 
<!-- Check to see if the file exists -->
<xsl:choose>
<xsl:when test="file:fileExists($filePath)">
    File exists... process the file here and output some stuff!
</xsl:when>
<xsl:otherwise>
    File does not exist. perform fallback operation!
</xsl:otherwise>
</xsl:choose>




3. Now the XSL knows out our functions and were consuming one of them, we just need to write the namespace itself and apply to to the transformation! Create a class in C# and add some functionality that you wish to make available to your XSL file.

Example:
// <copyright file="XSLFileHelper.cs" company="Ginko Solutions">
// Copyright (c) 2011 All Right Reserved
// </copyright>
// <author>Sean Greasley</author>
// <email>sean.greasley@fusedigital.com</email>
// <summary>Provides file functionality to support XSL processing</summary>
namespace RegulationExplorerWebHTML.Helpers
{
    using System;
    using System.IO;
    using System.Web;
 
    /// <summary>
    /// Provides file functionality to support XSL processing
    /// </summary>
    public class XSLFileHelper
    {
        public bool fileExists(string file)
        {
            // Get path
            string path = HttpContext.Current.Server.MapPath(file);
 
            // Exists<?>
            return File.Exists(path);
        }
    }
}




4. The final step is to apply this class to the transformation process! To do this, will use the AddExtensionObject method of the XsltArgumentList class.

Note: Please see my previous post about how to do an XML/XSL transformation in C# with parameters and settings.

Example:
XsltArgumentList xslArgs = new XsltArgumentList();
xslArgs.AddExtensionObject("urn:schemas-file", new XSLFileHelper());




5. and thats it!

No comments: