Now that you know all about creating and manipulating XML it is time to introduce Extensible Stylesheet Language Translations, or XSLT. XSLT is used to transform XML documents into another format altogether. One popular use of XSLT is to transform XML into HTML so that XML documents can be presented visually. The idea is to use an alternate language (XSLT) to transform the XML, rather than rewrite the source code, SQL commands, or some other mechanism used to generate XML.
Conceptually, XSLT is straightforward. A file (an .xsl file) describes the changes (transformations) that will be applied to a particular XML file. Once this is completed, an XSLT processor is provided with the source XML file and the XSLT file, and performs the transformation. The System.Xml.Xsl.XslTransform class is such an XSLT processor. Another processor you will find (introduced in the .NET Framework 2.0) is the XsltCommand object found at SystemXml.Query.XsltCommand. This section looks at using both of these processors.
You can also find some features in Visual Studio that deal with XSLT. The IDE supports items such as XSLT data breakpoints and XSLT debugging. Additionally, XSLT style sheets can be compiled into assemblies even more easily with the command-line style sheet compiler, XSLTC.exe.
The XSLT file is itself an XML document. Dozens of XSLT commands can be used in writing an XSLT file. The first example explores the following XSLT elements (commands):
<xsl:for-each select = "FilmOrderList/multiFilmOrders/FilmOrder">.
You can use XSLT to convert an XML document to generate a report that is viewed by the manager of the movie supplier. This report is in HTML form so that it can be viewed via the Web. The XSLT elements you previously reviewed (stylesheet, template, and for-each) are the only XSLT elements required to transform the XML document (in which data is stored) into an HTML file (data that can be displayed).
The example for this section relates to the Transformation project. This project includes the following XSLT file (code file: DisplayOrders.xslt):
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <html> <head><title>What people are ordering</title> </head> <body> <table border="1"> <tr> <th> Film Name </th> <th> Film ID </th> <th> Quantity </th> </tr> <xsl:for-each select= "//FilmOrder"> <tr> <td> <xsl:value-of select="Title" /> </td> <td> <xsl:value-of select="@id" /> </td> <td> <xsl:value-of select="Quantity" /> </td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>
In the preceding XSLT file, the XSLT elements are marked in bold. These elements perform operations on the source XML file, Filmorama.xml, containing a serialized FilmOrderList object, and generate the appropriate HTML file.
Your generated file contains a table (marked by the table tag, <table>) that contains a set of rows (each row marked by a table row tag, <tr>). The columns of the table are contained in table data tags, <td>. The XSLT element, for-each, is used to traverse each <FilmOrder> element, producing a separate row for each.
In this case, a shorthand for the location of the FilmOrder element was used: //FilmOrder returns all FilmOrder elements, regardless of their depth in the XML file. Alternately, you could have specified the full path using FilmOrderList/FilmOrders/FilmOrder here.
The individual columns of data are generated using the value-of XSLT element, in order to query the elements contained within each <FilmOrder> element (<Title>, <id>, and <Quantity>).
The code in Sub Main() to create a displayable XML file using the XslCompiledTransform object is as follows (code file: Main.vb):
Dim xslt As New XslCompiledTransform Dim outputFile As String = "output.html" xslt.Load("displayorders.xslt") xslt.Transform("filmorama.xml", outputFile) Process.Start(outputFile)
This consists of only five lines of code, with the bulk of the coding taking place in the XSLT file. The previous code snippet created an instance of a System.Xml.Xsl.XslCompiledTransform object named xslt. The Load method of this class is used to load the XSLT file you previously reviewed, DisplayOrders.xslt. The Transform method takes a source XML file as the first parameter, which in this case was a file containing a serialized FilmOrderList object. The second parameter is the destination file created by the transform, Output.html. The Start method of the Process class is used to display the HTML file in the system default browser. This method launches a process that is best suited for displaying the file provided. Basically, the extension of the file dictates which application will be used to display the file. On a typical Windows machine, the program used to display this file is Internet Explorer, as shown in Figure 8.7.
As demonstrated, the backbone of the System.Xml.Xsl namespace is the XslCompiledTransform class. This class uses XSLT files to transform XML documents. XslCompiledTransform exposes the following methods and properties:
myXslTransform.Transform("FilmOrders.xml", destFileName)
The first parameter to the Transform method can also be specified as IXPathNavigable or XmlReader. The XML output can be sent to an object of type Stream, TextWriter, or XmlWriter. In addition, a parameter containing an object of type XsltArgumentList can be specified. An XsltArgumentList object contains a list of arguments that are used as input to the transform. These may be used within the XSLT file to affect the output.
The first example used four XSLT elements to transform an XML file into an HTML file. Such an example has merit, but it doesn't demonstrate an important use of XSLT: transforming XML from one standard into another standard. This may involve renaming elements/attributes, excluding elements/attributes, changing data types, altering the node hierarchy, and representing elements as attributes, and vice versa.
Returning to the example, a case of differing XML standards could easily affect your software that automates movie orders coming into a supplier. Imagine that the software, including its XML representation of a movie order, is so successful that you sell 100,000 copies. However, just as you are celebrating, a consortium of the largest movie supplier chains announces that they are no longer accepting faxed orders and that they are introducing their own standard for the exchange of movie orders between movie sellers and buyers.
Rather than panic, you simply ship an upgrade that includes an XSLT file. This upgrade (a bit of extra code plus the XSLT file) transforms your XML representation of a movie order into the XML representation dictated by the consortium of movie suppliers. Using an XSLT file enables you to ship the upgrade immediately. If the consortium of movie suppliers revises their XML representation, then you are not obliged to change your source code. Instead, you can simply ship the upgraded XSLT file that ensures each movie order document is compliant.
This new example can be found in the Transformation2 project. This project includes the MovieOrdersOriginal.xml file, which is no different than the Filmorama.xml file used in the previous example. This document represents the original source file.
The project also includes the ConvertLegacyToNewStandard.xslt file. This file is the XSLT transform that is responsible for transforming the source file into the new format as follows (code file: ConvertLegacyToNewStandard.xslt):
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="FilmOrders"> <xsl:element name="DvdOrders"> <xsl:attribute name="Count"> <xsl:value-of select="count(FilmOrder)"/> </xsl:attribute> <xsl:for-each select="FilmOrder"> <xsl:element name="DvdOrder"> <xsl:attribute name="HowMuch"> <xsl:value-of select="Quantity"/> </xsl:attribute> <xsl:attribute name="FilmOrderNumber"> <xsl:value-of select="@id"/> </xsl:attribute> </xsl:element> </xsl:for-each> </xsl:element> </xsl:template> </xsl:stylesheet>
In the previous snippet of XSLT, the following XSLT elements are used to facilitate the transformation:
Several new XSLT terms have crept into your vocabulary: element, attribute, and for-each. Using the element node in an XSLT places an element in the destination XML document, while an attribute node places an attribute in the destination XML document. The for-each element iterates over all of the specified elements in the document.
Now that you have and understand the XSLT, here is the code to perform the actual transform (code file: Main.vb):
Dim xslt As New XslCompiledTransform Dim outputFile As String = "MovieOrdersModified.xml" xslt.Load("ConvertLegacyToNewStandard.xslt") xslt.Transform("MovieOrdersOriginal.xml", outputFile)
Those lines of code accomplish the following:
Recall that the input XML document (MovieOrdersOriginal.xml) does not match the format required by your consortium of movie supplier chains. The content of this source XML file is as follows:
<?xml version="1.0" encoding="utf-8" ?> <FilmOrderList> <FilmOrders> <FilmOrder> <name>Grease</name> <filmId>101</filmId> <quantity>10</quantity> </FilmOrder> … </FilmOrders> </FilmOrderList>
The format exhibited in the preceding XML document does not match the format of the consortium of movie supplier chains. To be accepted by the collective of suppliers, you must transform the document as follows:
Many of the steps performed by the transform could have been achieved using an alternative technology. For example, you could have used Source Code Style attributes with your serialization to generate the correct XML attribute and XML element name. Had you known in advance that a consortium of suppliers was going to develop a standard, you could have written your classes to be serialized based on the standard. The point is that you did not know, and now one standard (your legacy standard) has to be converted into a newly adopted standard of the movie suppliers' consortium. The worst thing you could do would be to change your working code and then force all users working with the application to upgrade. It is vastly simpler to add an extra transformation step to address the new standard.
The file produced by this example looks like this (code file: MovieOrdersModified.xml):
<?xml version="1.0" encoding="UTF-8"?> <DvdOrders count="3"> <DvdOrder FilmOrderNumber="101" HowMuch="10"/> <DvdOrder FilmOrderNumber="102" HowMuch="5"/> <DvdOrder FilmOrderNumber="103" HowMuch="25"/> </DvdOrders>
The preceding example spans several pages but contains just a few lines of code. This demonstrates that there is more to XML than learning how to use it in Visual Basic and the .NET Framework. Among other things, you also need a good understanding of XSLT, XPath, and XQuery. For more details on these standards, see Professional XML from Wrox.
You just took a good look at XSLT and the System.Xml.Xsl namespace, but there is a lot more to it than that. Other classes and interfaces exposed by the System.Xml.Xsl namespace include the following: