XSL Transformations

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):

  • stylesheet—This element indicates the start of the style sheet (XSL) in the XSLT file.
  • template—This element denotes a reusable template for producing specific output. This output is generated using a specific node type within the source document under a specific context. For example, the text <xsl: template match=”/”> selects all root nodes (“/”) for the specific transform template. The template is applied whenever the match occurs in the source document.
  • for-each—This element applies the same template to each node in the specified set. Recall the example class (FilmOrderList) that could be serialized. This class contained an array of movie orders. Given the XML document generated when a FilmOrderList is serialized, each movie order serialized could be processed using
 <xsl:for-each select = "FilmOrderList/multiFilmOrders/FilmOrder">.
  • value-of—This element retrieves the value of the specified node and inserts it into the document in text form. For example, <xsl:value-of select=”name” /> would take the value of the XML element <name> and insert it into the transformed document.

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.

Figure 8.7 Output for the Transformation example

8.7

Note
Don't confuse displaying this HTML file with ASP.NET. Displaying an HTML file in this manner takes place on a single machine without the involvement of a Web server.

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:

  • XmlResolver—This get/set property is used to specify a class (abstract base class, XmlResolver) that is used to handle external references (import and include elements within the style sheet). These external references are encountered when a document is transformed (the method, Transform, is executed). The System.Xml namespace contains a class, XmlUrlResolver, which is derived from XmlResolver. The XmlUrlResolver class resolves the external resource based on a URI.
  • Load—This overloaded method loads an XSLT style sheet to be used in transforming XML documents. It is permissible to specify the XSLT style sheet as a parameter of type XPathNavigator, filename of an XSLT file (specified as parameter type String), XmlReader, or IXPathNavigable. For each type of XSLT supported, an overloaded member is provided that enables an XmlResolver to also be specified. For example, it is possible to call Load(String, XsltSettings, XmlResolver), where String corresponds to a filename, XsltSettings is an object that contains settings to affect the transformation, and XmlResolver is an object that handles references in the style sheet of type xsl:import and xsl:include. It would also be permissible to pass in a value of Nothing for the third parameter of the Load method (so that no XmlResolver would be specified).
  • Transform—This overloaded method transforms a specified XML document using the previously specified XSLT style sheet. The location where the transformed XML is to be output is specified as a parameter to this method. The first parameter of each overloaded method is the XML document to be transformed. The most straightforward variant of the Transform method is Transform(String, String). In this case, a file containing an XML document is specified as the first parameter, and a filename that receives the transformed XML document is specified as the second. This is exactly how the first XSLT example utilized the Transform method:
 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.

XSLT Transforming between XML Standards

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:

  • <xsl:template match=”FilmOrders”>—All operations in this template XSLT element take place on the original document's FilmOrders node.
  • <xsl:element name=”DvdOrders”>—The element corresponding to the source document's FilmOrders element will be called DvdOrders in the destination document.
  • <xsl:attribute name=”Count”>—An attribute named Count will be created in the element <DvdOrders>.
  • <xsl:value-of select=”Quantity”>—Retrieve the value of the source document's <Quantity> element and place it in the destination document. This instance of XSLT element value-of provides the value associated with the attribute HowMuch.
  • <xsl:for-each select=”FilmOrder”>—Iterate over all <FilmOrder> elements.

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:

  • Create an XslCompiledTransform object
  • Use the Load method to load an XSLT file (ConvertLegacyToNewStandard.xslt)
  • Use the Transform method to transform a source XML file (MovieOrdersOriginal.xml) into a destination XML file (MovieOrdersModified.xml)

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:

  • Remove element <FilmOrderList>.
  • Rename element <FilmOrders> to <DvdOrders>.
  • Add a Count attribute to <DvdOrders>.
  • Rename element <FilmOrder> to <DvdOrder>.
  • Remove element <name>, since the film's name is not to be contained in the document.
  • Rename element <quantity> to HowMuch and make HowMuch an attribute of <DvdOrder>.
  • Rename element <filmId> to FilmOrderNumber and make FilmOrderNumber an attribute of <DvdOrder>.
  • Displays attribute HowMuch before attribute FilmOrderNumber.

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.

Other Classes and Interfaces in System.Xml.Xsl

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:

  • IXsltContextFunction—This interface accesses at run time a given function defined in the XSLT style sheet.
  • IXsltContextVariable—This interface accesses at run time a given variable defined in the XSLT style sheet.
  • XsltArgumentList—This class contains a list of arguments. These arguments are XSLT parameters or XSLT extension objects. The XsltArgumentList object is used in conjunction with the Transform method of XslTransform. Arguments enable you to use a single XSLT transformation for multiple uses, changing the parameters of the transformation as needed.
  • XsltContext—This class contains the state of the XSLT processor. This context information enables XPath expressions to have their various components resolved (functions, parameters, and namespaces).
  • XsltException, XsltCompileException—These classes contain the information pertaining to an exception raised while transforming data. XsltCompileException is derived from XsltException and is thrown by the Load method.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset