Using C# code in XSL Transformations

Home Articles Downloads Links About

Introduction

XSLT (Extensible StyleSheet Language Transformations) is used to transform XML documents into documents with different structure and format. XSLT includes over 100 built-in functions. But sometimes you may need an additional functionality that is not supported by XSLT. In these situations, XSLT scripting allows you to include embedded scripting using a script element. This article will present an example of using a custom C# script code in XSLT.

Example of using C# code in XSL Transformations

Download Example Source Code

The XSL transformation will be performed using the XslCompiledTransform class. The XslCompiledTransform class is an XSLT processor that supports the XSLT 1.0 syntax. It is a new implementation and includes performance gains when compared to the obsolete XslTransform class.

It will be transformed the following xml:

Contacts.xml

<?xml version="1.0" encoding="UTF-8"?>
<
Contacts>
 
<
Contact id="mailto:bob.thomas@smithdrug.com">
      
<
partnerId>0714141073460</partnerId>
      
<
enabled>true</enabled>          
      
<
firstName>Bob</firstName>
      
<
lastName>Thomas</lastName>
      
<
title>Operations Manager</title>
      
<
telephone>415-555-3299</telephone>
      
<
url>http://www.smithdrug.com/operations</url>
      
<
certificate>CertBob</certificate>
       <
certExpDate>2008-01-11T10:20:34.789Z
       </
certExpDate>             

   </Contact>
   <
Contact id="mailto:joe.brown@smithdrug.com">  
       
<partnerId>0714141073460</partnerId>
      
<
enabled>true</enabled>
      
<
firstName>Joe</firstName>
      
<
lastName>Brown</lastName>
      
<
title>Shipping Manager</title>
      
<
telephone>415-555-3298</telephone>
      
<
url>http://www.smithdrug.com/shipping</url>
      
<
certificate>CertJoe</certificate>
      
<
certExpDate>2008-01-11T10:20:34.789Z
       </
certExpDate>

   
</
Contact>
</
Contacts>

The xml will be transformed in simple Html using the following XSLT:

Contacts.xsl

<?xml version="1.0" encoding="utf-8"?>
<
xsl:stylesheet version="1.0"
   
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
   
xmlns:my-scripts="urn:my-scripts"
 
>
<
msxsl:script language="C#" implements-prefix="my-scripts">
<
msxsl:assembly name="System.Web"/>
<
msxsl:using namespace="System.Web"/>

<![CDATA[

    /// <summary>
    /// Try to format a DateTime string with particular format.
    /// </summary>
    /// <param name="aDateTime">DateTime string. Example: 2008-01-11T10:20:34.789Z</param>
    /// <param name="DateTimeFormat">DateTime format specifier. Examples: "d", "D", "R", "G", "M", "O", "U", etc.</param>

    /// <returns>Formated string. NOTE: On error returns the original string</returns>

    public static string FormatDate(string aDateTime, string DateTimeFormat)
    {
        try
        {
            string DateTimeFormatedString = aDateTime;

            if (!string.IsNullOrEmpty(aDateTime))
            {
                // Try to convert it to DateTime and format it with format specifier
                DateTimeFormatedString = DateTime.Parse(aDateTime).ToString(DateTimeFormat);
            }
            return DateTimeFormatedString;
        }
        catch
        {

            // On error returns the original string
            return aDateTime;
        }
    }

    /// <summary>
    /// Encode Url
    /// </summary>
    /// <param name="Url">Url string</param>

    /// <returns>Encoded url. On error the original string</returns>
    public static string UrlEncode(string Url)
    {
        try
        {
            return HttpUtility.UrlEncode(Url);
        }
        catch
        {
            return Url;
        }
    }

]]>
</
msxsl:script>
 
<
xsl:template match="/">
 
<
html>
     
<
head>
           
<
style type="text/css">

                  table.stats
                  {
                  text-align: center;
                  font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
                  font-weight: normal;
                  font-size: 11px;
                  color: #fff;
                  width: 280px;
                  background-color: #666;
                  border: 0px;
                  border-collapse: collapse;
                  border-spacing: 0px;
                  }

                  table.stats td
                  {
                  background-color: #CCC;
                  color: #000;
                  padding: 4px;
                  text-align: left;
                  border: 1px #fff solid;
                  }

                  table.stats td.hed
                  {
                  background-color: #666;
                  color: #fff;
                  padding: 4px;
                  text-align: left;
                  border-bottom: 2px #fff solid;
                  font-size: 12px;
                  font-weight: bold;
                  }

           
</
style>
     
</
head>
     
<
body>
   
<
table class="stats" cellspacing="0">
     
<
tr class="hed">
       
<
th>Title</th>
       
<
th>Name</th>
       
<
th>Web Site</th>
       
<
th>Certificate</th>
       
<
th>Certificate expiration date</th>
     
</
tr>
     
<
xsl:for-each select="Contacts/Contact">
       
<
tr>
         
<
td>
           
<
xsl:value-of select="title"/>
         
</
td>
         
<
td>
           
<
xsl:value-of select="concat(firstName,' ', lastName)"/>
         
</
td>
         
<
td>
           
<
a target="_blank">
              
<
xsl:attribute name="href">
                            
      <
xsl:value-of select="url"/>
              
</
xsl:attribute>
              
<
xsl:value-of select="url"/>
            
</
a>
          
</
td>
         
<
td>
           
<
xsl:value-of select="certificate"/>
         
</
td>
         
<
td>
           
<
xsl:value-of select="my-scripts:FormatDate(certExpDate,'F')"/>
         
</
td>
       
</
tr>
     
</
xsl:for-each>
   
</
table>
     
</
body>
  
</
html>
 
</
xsl:template>
</
xsl:stylesheet>

Finally, for the transformation and rendering the generated Html I use a simple aspx page:

<%@ Page Language="C#" AutoEventWireup="true" %>
<
html xmlns="http://www.w3.org/1999/xhtml" >
<
head runat="server">
   
<title>Untitled Page</title>
   
<script language="C#" runat="server">
       
void Page_Load(Object Sender, EventArgs e)
       
{
           
// Set XML and XSL file path
           
string XmlFile = Request.PhysicalApplicationPath + @"App_Data\Contacts.xml";

            string XsltFile = Request.PhysicalApplicationPath + @"App_Data\Contacts.xsl";

            // Load the XSL file
           
System.Xml.Xsl.XsltSettings xsltSettings = new System.Xml.Xsl.XsltSettings();
           
xsltSettings.EnableScript = true;
           
System.Xml.Xsl.XslCompiledTransform xsltrans = new System.Xml.Xsl.XslCompiledTransform();
           
System.Xml.XmlUrlResolver resolver = new System.Xml.XmlUrlResolver();
           
resolver.Credentials = System.Net.CredentialCache.DefaultCredentials;
           
xsltrans.Load(XsltFile, xsltSettings, resolver);
           
// Load the XML source file.
           
System.Xml.XPath.XPathDocument xmlDoc = new System.Xml.XPath.XPathDocument(XmlFile);
           
// Generate XSL transform output
           
StringBuilder sbOutput = new StringBuilder();
           
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
           
settings.OmitXmlDeclaration = true;
           
settings.Indent = true;
           
using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sbOutput, settings))
           
{
               
System.Xml.Xsl.XsltArgumentList xsltArgList = new System.Xml.Xsl.XsltArgumentList();
               
xsltrans.Transform(xmlDoc, xsltArgList, writer);
               
// Send the generated html to the client
               
Response.Write(sbOutput.ToString());
           
}
           
Response.End();
       
}
   
</script>

</head>
<
body>
</
body>
</
html>

The aspx page task is only to load the Contacts.xml and Contacts.xsl files and transform the XML using XslCompiledTransform class. Therefore, I will not concentrate on this part.

The interesting part is the XSL file Contacts.xsl. This is where it is included the C# custom code.

The custom methods are defined in script element. When the style sheet is loaded, any defined functions are compiled to Microsoft intermediate language (MSIL) by being wrapped in a class definition.

<msxsl:script language="C#" implements-prefix="my-scripts">

<![CDATA[

]]>
</msxsl:script>

According to the MSDN library, the language attribute is not mandatory, but if specified, it must have one of the following values: C#, VB, JScript, JavaScript, VisualBasic, or CSharp. If not specified, the language defaults to JScript.

The implements-prefix attribute is mandatory. This attribute is used to declare a namespace and associate it with the script block. The value of this attribute is the prefix that represents the namespace.

msxsl is a prefix bound to the namespace urn:schemas-microsoft-com:xslt. Because the msxsl:script element belongs to the namespace urn:schemas-microsoft-com:xslt, the style sheet must include the namespace declaration xmlns:msxsl=urn:schemas-microsoft-com:xslt.

<xsl:stylesheet version="1.0"
   
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   
xmlns:msxsl="urn:schemas-microsoft-com:xslt"   
    xmlns:my-scripts
="urn:my-scripts">

Also, this is the place to include the namespace associated with the script block. In the example it is my-scripts.

Now it’s time for the custom code in the script block. In the example I define the method FormatDate and use it for converting and formatting the XML date string:

/// <summary>
/// Try to format a DateTime string with particular format.
/// </summary>
/// <param name="aDateTime">DateTime string. Example: 2008-01-11T10:20:34.789Z</param>
/// <param name="DateTimeFormat">DateTime format specifier. Examples: "d", "D", "R", "G", "M", "O", "U", etc.</param>
/// <returns>Formated string. NOTE: On error returns the original string</returns>

public static string FormatDate(string aDateTime, string DateTimeFormat)
{
        try
        {
            string DateTimeFormatedString = aDateTime;

            if (!string.IsNullOrEmpty(aDateTime))
            {
                // Try to convert it to DateTime and format it with format specifier
                DateTimeFormatedString = DateTime.Parse(aDateTime).ToString(DateTimeFormat);
            }
            return DateTimeFormatedString;
        }
        catch
        {
            // On error returns the original string
            return aDateTime;
        }
}

In the XSLT file, I use FormatDate method by just calling the it and passing the required parameters

<xsl:value-of select="my-scripts:FormatDate(certExpDate,'F')"/>

The “certExpDate” value is retrieved from the XML “certExpDate” element.

You can also include custom code from different assembly.

By default only the following namespaces are supported: System, System.Collection, System.Text, System.Text.RegularExpressions, System.Xml, System.Xml.Xsl, System.Xml.XPath, and Microsoft.VisualBasic

In the example, I include the System.Web assembly and namespace.

<msxsl:assembly name="System.Web"/>
<
msxsl:using namespace="System.Web"/>

In the example I define the method UrlEncode that use the class HttpUtility from the System.Web assembly.

NOTE: If you use msxsl:assembly with the obsolete class XslTransform you may receive the following error:

“The 'msxslcript' element cannot be empty.”

Google Ads