One of the main benefits of XML is that it separates data from its presentation. Without further elaboration, this claim seems ordinary. However, if you combine XML data with an XSL Transformations (XSLT) style sheet, you will then have a powerful way to dynamically transform and present information in any format you want. Furthermore, often the structure of an XML document created by one application does not match the structure required by the other application to process that XML data. To transform the existing XML data structure into one that can be processed, you need to use XSLT. Having realized the need for an efficient built-in support for XSLT processing, Microsoft has built a set of highly optimized classes into the .NET Framework 2.0 that are robust and scalable. This article will explore the rich XSLT support provided by the .NET Framework 2.0 by providing examples on how to use the XSLT related classes to create rich ASP.NET Web applications.
Introduction
The core XSLT related classes are contained in the System.Xml.Xsl namespace and are as follows:
- XslCompiledTransform – Core class that acts as the XSLT processor in .NET Framework 2.0. Used to transform XML data into other structures such as HTML, Text or another XML.
- XsltArgumentList – Allows you to pass a variable number of parameters and extension objects to an XSL style sheet.
- XsltCompileException – This exception is thrown by the Load() method when an error occurs in the XSL style sheet.
- XsltException – This exception is thrown if an exception occurs during the processing of an XSL style sheet.
Note that the XslTransform class used for XSL transformations in .NET Framework 1.x is now obsolete and replaced by the new XslCompiledTransform class. In addition to better performance, the XslCompiledTransform also provides better support for the XSLT 1.0 specification. Starting from .NET Framework 2.0, the recommended approach to performing XSL transformations is through the XslCompiledTransform class. Because of the similarity in design to the XslTransform class, you can easily migrate your existing code to utilize the XslCompiledTransform class.
Before looking at the code sample, let us have a brief look at the important methods of the XslCompiledTransform class that will be required.
- Load – This method has several overloads and it provides for loading of an XSL stylesheet into an XslCompiledTransform object from any one of the following resources: a string that specifies the URL, from an XmlReader object, or from an XPathNavigator object, and so on.
- Transform – Allows you to transform the XML data into a specified format using the stylesheet that is already loaded (using the Load method).
Implementation
Now that you have had an overview of the XSLT classes and its methods, let us start by looking at a simple XSL transformation example. For the purposes of this article, you will retrieve the data from AdventureWorks database in the form of XML data and transform it using XSLT to render the data as HTML in the browser.
Simple XSL Transformation
In this example, you will create a simple ASP.NET page that retrieves categories data from the as XML stream and transform that into HTML so that it can be displayed in the browser. Before looking at the ASP.NET page, let us look at the XSL file named Category.xsl.
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>Simple XSLT Transformation</TITLE>
</HEAD>
<BODY>
<H2>Simple XSLT Transformation</H2>
<table border="1" cellSpacing="1" cellPadding="1">
<center>
<xsl:for-each select="//Categories">
<!-- Each record on a seperate row -->
<xsl:element name="tr">
<xsl:element name="td">
<xsl:value-of select="ProductSubcategoryID" />
</xsl:element>
<xsl:element name="td">
<xsl:value-of select="Name" />
</xsl:element>
<xsl:element name="td">
<xsl:attribute name="align">center</xsl:attribute>
<xsl:value-of select="ModifiedDate" />
</xsl:element>
</xsl:element>
</xsl:for-each>
</center>
</table>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
The XSL file basically contains the logic to loop through all the elements contained in the Categories element. The code for the ASP.NET page is as follows:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Xml.Xsl" %>
<%@ Import Namespace="System.Xml.XPath" %>
<%@ Import Namespace="System.Web.Configuration" %>
<script runat="server">
void Page_Load(object sender, System.EventArgs e)
{
string connString = WebConfigurationManager.ConnectionStrings
["adventureWorks"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connString))
{
connection.Open();
SqlCommand command = new SqlCommand
("Select * from Production.ProductSubcategory as Categories " +
" for xml auto,elements", connection);
XmlReader reader = command.ExecuteXmlReader();
XPathDocument xpathDoc = new XPathDocument(reader);
string xslPath = Server.MapPath("App_Data/Category.xsl");
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(xslPath);
transform.Transform(xpathDoc, null, Response.Output);
}
}
</script>
In the Page_Load event of the Web form, you retrieve the data (in the form of XML) from the ProductSubcategory table and then apply an external XSLT stylesheet (named Category.xsl) on the XML data to emit HTML. You then write this HTML directly onto the client browser. This is accomplished by passing in the Response.Output object to the Transform() method. Note that in the above example, the XPathDocument class is used for loading the XML document because this class is optimized to provide high-performance XML document processing. If you navigate to the page using the browser, you will see the below output.
Passing Parameters to an XSLT Style Sheet
Similar to the way you pass parameters to a method or function, you can also parameters to an XSLT style sheet. Passing a parameter to a style sheet gives you the ability to initialize a globally scoped variable, which is defined as any <xsl:param> that is a child of the <xsl:stylesheet> element. The code shown in bold show the lines of code where the parameter is declared and then used.
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />
<xsl:param name="BackGroundColor" select="Blue" />
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>Passing Parameters to an XSLT Style Sheet</TITLE>
</HEAD>
<BODY>
<H2> Passing Parameters to an XSLT Style Sheet</H2>
<table border="1" cellSpacing="1" cellPadding="1">
<center>
<xsl:for-each select="//Categories">
<!-- Each record on a seperate row -->
<xsl:element name="tr">
<xsl:attribute name="bgcolor">
<xsl:value-of select="$BackGroundColor" />
</xsl:attribute>
<xsl:element name="td">
<xsl:value-of select="ProductSubcategoryID" />
</xsl:element>
<xsl:element name="td">
<xsl:value-of select="Name" />
</xsl:element>
<xsl:element name="td">
<xsl:attribute name="align">center</xsl:attribute>
<xsl:value-of select="ModifiedDate" />
</xsl:element>
</xsl:element>
</xsl:for-each>
</center>
</table>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
After the declaration of the BackGroundColor parameter, the code then uses the BackGroundColor parameter to specify the background color for the <tr> element in the table.
<xsl:value-of select="$BackGroundColor" />
Although the value of BackGroundColor was hard-coded in the declaration using the< xsl:param> element, ideally it should be passed from the calling ASP.NET page To accomplish this, you leverage the XsltArgumentList class. Specifically the AddParam() method of the XsltArgumentList provides this functionality. XsltArgumentList class is a key class that enables you to create XSLT reusable and maintainable style sheets by providing a mechanism to pass parameters to an XSLT style sheet.
To the AddParam() method, you supply a qualified name, the namespace URI and value. If the parameter value is not a String, Boolean, Number, Node Fragment, or NodeSet, it will be forced to a double or string. The ASP.NET calling page that passes parameters to the style sheet is shown below.
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Xml.Xsl" %>
<%@ Import Namespace="System.Xml.XPath" %>
<%@ Import Namespace="System.Web.Configuration" %>
<script runat="server">
void Page_Load(object sender, System.EventArgs e)
{
string connString = WebConfigurationManager.ConnectionStrings
["adventureWorks"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connString))
{
connection.Open();
SqlCommand command = new SqlCommand
("Select * from Production.ProductSubCategory as Categories " +
" for xml auto,elements", connection);
XmlReader reader = command.ExecuteXmlReader();
XPathDocument xpathDoc = new XPathDocument(reader);
string xslPath = Server.MapPath("App_Data/Category.xsl");
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(xslPath);
XsltArgumentList argsList = new XsltArgumentList();
string backGroundColor = "Tan";
//Add the required parameters to the XsltArgumentList object
argsList.AddParam("BackGroundColor", "", backGroundColor);
transform.Transform(xpathDoc, argsList, Response.Output);
}
}
</script>
The above code is very similar to the first example except for the difference that this example uses the XsltArgumentList object. Specifically you create an instance of the XsltArgumentList object, invoke its AddParam() method to add the BackGroundColor parameter, and finally pass the XsltArgumentList as an argument to the Transform() method of the XslCompiledTransform. With all these enhancements in place, pointing the browser to the URL of the Web page results in the following output wherein all the categories records are displayed with the Tan background color.
Invoking Extension Objects from an XSLT Style Sheet
In addition to allowing you to pass parameters, the XsltArgumentList class also provides you with the ability to associate a class with the namespace URI, using which you can call the methods of a class directly from a stylesheet. The object whose methods are invoked from the stylesheet is called Extension object. For the purposes of this example, let us create an extension object named DateTimeConverter to format the ModifiedDate value to the appropriate format. To this end, let us create the DateTimeConverter class with only one method named ToDateTimeFormat() that formats the input date value based on the supplied format string.
using System;
public class DateTimeConverter
{
public DateTimeConverter()
{}
public string ToDateTimeFormat(string data, string format)
{
DateTime date = DateTime.Parse(data);
return date.ToString(format);
}
}
Place the DateTimeConverter class in the App_Code folder so that it can then be easily referred to from the ASP.NET page. To be able to invoke the extension object from the XSLT style sheet, you need to do the following:
- Declare an alias for the extension object namespace at the top of the XSLT file
- Invoke the method of the extension object using the alias
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:DateTimeConverter="urn:DateTimeConverter">
<xsl:output method="html" />
<xsl:param name="BackGroundColor" select="Blue" />
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>Invoking extension objects from an XSLT Style Sheet</TITLE>
</HEAD>
<BODY>
<H2>Invoking extension objects from an XSLT Style Sheet</H2>
<table border="1" cellSpacing="1" cellPadding="1">
<center>
<xsl:for-each select="//Categories">
<!-- Each record on a seperate row -->
<xsl:element name="tr">
<xsl:attribute name="bgcolor">
<xsl:value-of select="$BackGroundColor" />
</xsl:attribute>
<xsl:element name="td">
<xsl:value-of select="ProductSubcategoryID" />
</xsl:element>
<xsl:element name="td">
<xsl:value-of select="Name" />
</xsl:element>
<xsl:element name="td">
<xsl:attribute name="align">center</xsl:attribute>
<xsl:value-of select="DateTimeConverter:ToDateTimeFormat
(ModifiedDate, 'F')" />
</xsl:element>
</xsl:element>
</xsl:for-each>
</center>
</table>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
As you can see, the adjustments made to the stylesheet are minimal. To the xsl:stylesheet element, you add the attribute xmlns:DateTimeConverter=”urn:DateTimeConverter”. This is done to associate a namespace URI for our extension object. The following line of code creates the association.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:DateTimeConverter="urn:DateTimeConverter">
Once you have the association between the object and the namespace URI in place, you can then easily invoke the methods of the extension object from the stylesheet as if it is part of the stylesheet.
The following line of code demonstrates this.
<xsl:value-of select="DateTimeConverter:ToDateTimeFormat(ModifiedDate, 'F')" />
In the above line, you invoke the ToDateTimeFormat() method of the DateTimeConverter class, passing to it the ModifiedDate and the desired date format string.
Now that you have had a look at the changes to the style sheet, let us turn our focus to the code required to pass the extension object to the stylesheet so that it can invoke the methods of the extension object.
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Xml.Xsl" %>
<%@ Import Namespace="System.Xml.XPath" %>
<%@ Import Namespace="System.Web.Configuration" %>
<script runat="server">
void Page_Load(object sender, System.EventArgs e)
{
string connString = WebConfigurationManager.ConnectionStrings
["adventureWorks"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connString))
{
connection.Open();
SqlCommand command = new SqlCommand
("Select * from Production.ProductSubCategory as Categories " +
" for xml auto,elements", connection);
XmlReader reader = command.ExecuteXmlReader();
XPathDocument xpathDoc = new XPathDocument(reader);
string xslPath = Server.MapPath("App_Data/Category.xsl");
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(xslPath);
XsltArgumentList argsList = new XsltArgumentList();
string backGroundColor = "Tan";
//Add the required parameters to the XsltArgumentList object
argsList.AddParam("BackGroundColor", "", backGroundColor);
//Create and add the extension object to the XsltArgumentList
DateTimeConverter converter = new DateTimeConverter();
argsList.AddExtensionObject("urn:DateTimeConverter", converter);
transform.Transform(xpathDoc, argsList, Response.Output);
}
}
</script>
Let us walk through the important lines of the code.
In this line, you create an instance of the BGColor class.
DateTimeConverter converter = new DateTimeConverter();
After you create an instance of the object, the next step would be to add the instantiated object to the XsltArgumentList object.
argsList.AddExtensionObject("urn:DateTimeConverter",converter);
Finally, you pass the instantiated object along with the rest of the parameters to the stylesheet using the following line of code.
transform.Transform(xpathDoc,argsList,Response.Output);
Executing the above code results in the following output.
As you can see from the above output, the ModifiedDate value is appropriately formatted.
Conclusion
In this article, you have seen the following.
- How to transform an XML document using an XSLT stylesheet.
- How to supply parameters to an XSLT stylesheet using XsltArgumentList class.
- How to invoke methods of an extension object from an XSLT stylesheet.
- How to filter a set of nodes using an XPath expression.
Although the application we created was simple in functionality, it should provide a solid foundation for understanding how to create applications using XSLT related classes in the .NET Framework 2.0.
Download
You can download a zip file containing the complete source code of the scripts and files discussed in this article from here: xsltransformations.zip.