How to apply XSLT Transformation to a XML or to a .NET Object

What is a XSLT (Extensible Stylesheet Language Transformation)?

We could use this to transform input XML into any output type (XHTML, TXT etc). XSL describes how the XML document should be displayed. In an XSL transformation, an XSLT processor reads both an XML document and an XSLT style sheet. Based on the instructions the processor finds in the XSLT style sheet, we could create different output documents (XHTML, TXT etc).

XSLT style sheet documents

All that an XSLT document contains is set of template rules. XSLT processor traverses through the XML document and wherever it finds the match between the template rule and the node, it simply applies the template.

Example:

In this article let’s look at how to create a XSLT document and use it in a .NET solution to transform an OBJECT into a HTML.

1) Create a new “Console Application” in Visual Studio.

2) Create a simple Book class.

public class Book { public int? BookID; public string BookName; public string BookAuthor; public decimal BookAmount; public decimal BookCurrencyID; }

3) Add a new item of type XSLT to the project. Rename it to Book.XSLT

<!--DVFMTSC--><!--?<span class="hiddenSpellError" pre=""-->xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsl:template match="ArrayOfBook"> <html> <body> <table> <tr><td>BOOKS </td></tr> </table> <table border='1' cellpadding='3' cellspacing= '0' > <tr> <th>Book ID</th> <th>Book Name</th> <th>Book Author</th> <th>Book Amount</th> </tr> <!--Iterating through the collection of book objects--> <xsl:for-each select="Book"> <!--if BookID is not populated it is not a valid book--> <xsl:if test="string(number(BookID)) != 'NaN'"> <tr> <td><xsl:value-of select="BookID"/></td> <td><xsl:value-of select="BookName"/></td> <td><xsl:value-of select="BookAuthor"/></td> <td> <!--Added some custom formatting to print amount based on currency ID --> <xsl:choose> <xsl:when test="string(BookCurrencyID) = 1"> $ <xsl:value-of select="BookAmount"/> <!--DVFMTSC--><!--<span class="hiddenSpellError" pre=""-->xsl:when> <xsl:when test="string(BookCurrencyID) = 2"> Rs <xsl:value-of select="BookAmount"/> <!--DVFMTSC--><!--<span class="hiddenSpellError" pre=""-->xsl:when> <xsl:otherwise> - <!--DVFMTSC--><!--<span class="hiddenSpellError" pre=""-->xsl:otherwise> <!--DVFMTSC--><!--<span class="hiddenSpellError" pre=""-->xsl:choose> </td> </tr> <!--DVFMTSC--><!--<span class="hiddenSpellError" pre=""-->xsl:if> <!--DVFMTSC--><!--<span class="hiddenSpellError" pre=""-->xsl:for-each> </table> <br/> </body> </html> <!--DVFMTSC--><!--<span class="hiddenSpellError" pre=""-->xsl:template> <!--DVFMTSC--><!--<span class="hiddenSpellError" pre=""-->xsl:stylesheet>

4) Create Pre-Build event to copy the XSLT to desired location

xcopy $(ProjectDir)Book.xslt $(TargetDir) /d /Y /I

5) This example uses the XslCompiledTransform.Transform method to transform the books.xml file to the books.html file using the transform.xsl style sheet.

input — An object implementing the IXPathNavigable interface. In the Microsoft .NET Framework, this can be either an XmlNode (typically an XmlDocument), or an XPathDocument containing the data to be transformed. In this example, we loaded the XMLPathDocument with the serlialized xml string of the source object

StringWriter swwriter = new StringWriter(); XmlSerializer serializer = new XmlSerializer(sourceObject.GetType()); serializer.Serialize(swwriter, sourceObject); StringReader sr = new StringReader(swwriter.ToString()); XPathDocument doc = new XPathDocument(sr);

results — The XmlWriter to which you want to output. In this example, we are using StringWriter as our output stream

StringBuilder sbhtmlString = new StringBuilder(); StringWriter swWriter = new StringWriter(); XmlWriter writer = XmlWriter.Create(sbhtmlString); XmlTextWriter xmlwriter = new XmlTextWriter(swWriter); xmlwriter.Formatting = Formatting.Indented;

Lets put everything together and create a utility class that would transform any source object to a HTML output string.

public class XmlUtil { public static string PrepareHTMLFromXSL(object sourceObject, string xsl) { XmlReader xmlReader = null; string htmlContent = string.Empty; //Load the XSL into a xml reader StringReader sr = new StringReader(xsl); TextReader tr = sr; xmlReader = XmlReader.Create(tr); htmlContent = PrepareContent(sourceObject, xmlReader); return htmlContent; } public static string PrepareContent(object sourceObject, XmlReader xmlReader) { //Serialize the input object and load into xml document StringWriter swwriter = new StringWriter(); XmlSerializer serializer = new XmlSerializer(sourceObject.GetType()); serializer.Serialize(swwriter, sourceObject); StringReader sr = new StringReader(swwriter.ToString()); XPathDocument doc = new XPathDocument(sr); //output content is written to xmlwriter. initialize it with all settings StringBuilder sbhtmlString = new StringBuilder(); StringWriter swWriter = new StringWriter(); XmlWriter writer = XmlWriter.Create(sbhtmlString); XmlTextWriter xmlwriter = new XmlTextWriter(swWriter); xmlwriter.Formatting = Formatting.Indented; XslCompiledTransform xslTransform = new XslCompiledTransform(); xslTransform.Load(xmlReader); xslTransform.Transform(doc, xmlwriter); xmlwriter.Flush(); writer.Flush(); swWriter.Flush(); if (swWriter != null) { swWriter.Close(); swWriter.Dispose(); } if (xslTransform != null) { xslTransform = null; } if (writer != null) { writer.Close(); writer = null; } if (xmlReader != null) { xmlReader.Close(); xmlReader = null; } if (doc != null) { doc = null; } if (xmlwriter != null) { xmlwriter.Close(); xmlwriter = null; } if (serializer != null) { serializer = null; } return swWriter.ToString(); } public static string SerializeObject<T>(object obj) { XmlSerializer serializer = new XmlSerializer(typeof(T)); using (StringWriter writer = new StringWriter()) { serializer.Serialize(writer, obj); return writer.ToString(); } } }

6) All that is left is to populate collection of books and consume these utility objects.

class Program { public static void Main(string[] args) { List<Book> books = new List<Book>(); Book book = new Book(); book.BookID = 1; book.BookName = "book1"; book.BookAuthor = "rowling"; book.BookAmount = 50; book.BookCurrencyID = 1; books.Add(book); book = new Book(); book.BookName = "book3"; book.BookAuthor = "james"; book.BookAmount = 5000; book.BookCurrencyID = 2; books.Add(book); book = new Book(); book.BookID = 2; book.BookName = "book2"; book.BookAuthor = "james"; book.BookAmount = 5000; book.BookCurrencyID = 2; books.Add(book); string xsl = RetrieveXslTemplate(); string html = XmlUtil.PrepareHTMLFromXSL(books, xsl); WriteToLog(html, @"C:\temp\book.html"); } private static string RetrieveXslTemplate() { using (StreamReader sr = new StreamReader("Book.xslt")) { return sr.ReadToEnd(); } } public static void WriteToLog(string str, string path) { using (StreamWriter sw = new StreamWriter(path)) { sw.WriteLine(str); } <!--wp_fromhtmlpreview_devfmt-->

<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <body> <table> <tr> <td>BOOKS </td> </tr> </table> <table border="1" cellpadding="3" cellspacing="0"> <tr> <th>Book ID</th> <th>Book Name</th> <th>Book Author</th> <th>Book Amount</th> </tr> <tr> <td>1</td> <td>book1</td> <td>rowling</td> <td>$ 50</td> </tr> <tr> <td>2</td> <td>book2</td> <td>james</td> <td>Rs 5000</td> </tr> </table> <br /> </body> </html>

7) Output HTML