Introduction
The .NET Framework provides XslCompiledTransform
which is an XSLT processor 1.0. However this doesn't mean that we
can’t work with XSLT 2.0 in .NET. This article is for folks who want
to use XSLT 2.0 in .NET.
XSLT 2.0 is richer than XSLT 1.0. Indeed,
below some features of XSLT 2.0.
- regular expressions
- current date time and multiple functions on dates
- grouping
-
xsl:function for camelcasing a string - string comparison
-
tokenize() and matches() -
for … in … return -
next-match -
as attribute on basic processors
All the functions and the specifications are described on W3C. You can also find all the functions on w3schools.
Saxon is an XSLT and XQuery processor created by Michael Kay.
There are open-source and also closed-source commercial versions.
Versions exist for Java and .NET. In this tutorial we will use Saxon
.NET API to illustrate how the XSLT processing is performed.
Using the code
Input
The XML file below contains a list of some cities, their country and the
population count.
="1.0" ="utf-8"
<cities>
<city name="Milano" country="Italia" pop="1307495" />
<city name="Paris" country="France" pop="2220140" />
<city name="Bordeaux" country="France" pop="719489" />
<city name="München" country="Deutschland" pop="1260391" />
<city name="Lyon" country="France" pop="474946" />
<city name="Venezia" country="Italia" pop="270801" />
<city name="Delft" country="Holland" pop="94512" />
<city name="Rotterdam" country="Holland" pop="607460" />
</cities>
Desired output
Generated at
22.12.2011 23:42:27
| Position |
Country |
City List |
Population |
| 1 |
France |
Paris, Bordeaux, Lyon |
3.414575E6 |
| 2 |
Italia |
Milano, Venezia |
1.578296E6 |
| 3 |
Deutschland |
München |
1.260391E6 |
| 4 |
Holland |
Delft, Rotterdam |
701972 |
XSLT Processing
We will make an XSLT to transform this XML file into an HTML report containing
the list of countries ordered by population count and for each country the list of its cities grouped.
In the XSLT below, I used xsl:for-each-group statement in order to group the cities by country.
It is
possible to set up the grouping in XSLT 1.0 by using xsl:key but It would be more complex.
Also,
you will notice that I used current-dateTime() function in order to retrieve the current date
time and format-dateTime() function in order to format the current date time.
="1.0" ="iso-8859-1"
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="iso-8859-1" />
<xsl:template match="/">
<html>
<head>
<title>Cities</title>
</head>
<body>
Generated at
<xsl:value-of select="format-dateTime(current-dateTime(), '[D].[M].[Y] [H]:[m]:[s]' )" />
<br />
<table style="border : 1px solid #000;">
<thead>
<tr>
<th>Position</th>
<th>Country</th>
<th>City List</th>
<th>Population</th>
</tr>
</thead>
<tbody>
<xsl:for-each-group select="cities/city" group-by="@country">
<xsl:sort select="sum(current-group()/@pop)" data-type="number" order="descending" />
<tr>
<td>
<xsl:value-of select="position()" />
</td>
<td>
<xsl:value-of select="@country" />
</td>
<td>
<xsl:value-of select="current-group()/@name" separator=", " />
</td>
<td>
<xsl:value-of select="sum(current-group()/@pop)" />
</td>
</tr>
</xsl:for-each-group>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
The code below performs the main XSLT processing by using the SAXON .NET API.
namespace Saxon
{
internal class Program
{
private static void Main()
{
const string xmlFile = @"..\..\cities.xml";
const string xsltFile = @"..\..\cities.xslt";
const string outFile = @"..\..\cities_grouped.html";
try
{
using (XmlReader xml = XmlReader.Create(xmlFile))
using (XmlReader xslt = XmlReader.Create(xsltFile))
{
var processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().
Build(xml);
XsltTransformer transformer = processor.NewXsltCompiler().
Compile(xslt).Load();
transformer.InitialContextNode = input;
var serializer = new Serializer();
serializer.SetOutputStream(new FileStream(outFile, FileMode.Create, FileAccess.Write));
transformer.Run(serializer);
Console.WriteLine("Output written to " + outFile + Environment.NewLine);
}
}
catch (Exception e)
{
ConsoleColor currentConsoleColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("oops : " + e.Message);
Console.ForegroundColor = currentConsoleColor;
}
Console.Write("Press any key to exit ...");
Console.ReadKey();
}
}
} Other options
There is
XQSharp, an XSLT, XPath 2.0 and XQuery 1.0 implementation for the .NET platform. And there is
AltovaXML, an XSLT 2.0 and XQuery 1.0 COM based software package for Windows that can be used with .NET too (via COM Interop).