Lesson 2: Using XSL Transformations
In this lesson, you ll learn about using XSL to transform XML files, using expressions written in XML path language (XPath).
After this lesson, you will be able to
Use the XML control to transform an XML data file into formatted HTML on a Web form
Explain the differences between XML and HTML
Create an XML file
Create XSL templates to control how the XML file is transformed into HTML
Use the XSL elements to repeat tasks, perform conditional operations, insert HTML elements, and sort output
Evaluate expressions using XPath
Estimated lesson time: 40 minutes
How XSL Transformations Work
XSL transformations use the XML server control to generate formatted output from an XML input file using a set of rules stored in an XSL description file. The XSL file is similar to the CSS file you learned about in the preceding lesson it provides the formatting rules that are applied to the output displayed on the Web form. Unlike CSS files, however, XSL files can position elements anywhere on the Web form and can perform logical operations, such as repeating and conditional operations.
You can think of XSL files as an intelligent formatting layer that complements rather than replaces CSS. Use XSL to place structured data on a Web form, and then use CSS to set the appearance of the elements within that layout.
To perform an XSL transformation on a Web form, follow these steps:
Add an XML server control to a Web form.
Set the control s DocumentSource property to the XML file to format.
Set the TransformSource property to the XSL file to use to format the output.
At run time, the XML server control processes the XML input using the XSL description to provide formatted output, as shown in Figure 13-13.
Figure 13-13. Performing XSL transformation
Creating an XML File
XML files are a way to describe structured data in text format. XML identifies data items using <element> </element> tags much the same as HTML. Unlike HTML, however, the rules of XML are strict:
In HTML, <li>, <br>, and other tags can exist without equivalent </li> or </br> tags. That is not allowed in XML.
In HTML, <P> and <p> are equivalent. In XML, they constitute different tags.
In HTML, you can omit quotation marks for numeric attributes such as <table cols=3>. In XML, you must always include the quotation marks: <table cols="3">.
For example, the following is OK in HTML: <b>Bold text<i>italic bold</b> regular italic</i>. However, in XML it must be written like this: <b>Bold text<i>italic bold</i></b> <i>regular italic</i>
These strict rules allow XML to have an important capability that HTML does not have: in XML, you can define your own tags, and you can assign those tags any meaning you choose.
To create an XML file in Visual Studio .NET, choose Add New Item from the Project menu, choose XML file from the Templates list, and then click Open.
When you create a new XML file, it s a good idea to first write out the tags and structure that you ll use throughout the document. This saves you the trouble of trying to retag elements if you discover that you missed something. For example, the following XML describes cookbook data that we ll be using as a sample in this lesson:
<cookbook> <title></title> <subtitle></subtitle> <description></description> <recipe> <title></title> <subtitle></subtitle> <description></description> <servings></servings> <ingredients> <ingredient> <name></name> <quantity></quantity> </ingredient> <ingredient> <name></name> <quantity></quantity> </ingredient> </ingredients> <instructions> <introduction></introduction> <step></step> <step></step> <step></step> <summary></summary> </instructions> </recipe> </cookbook>
The data for each of these items will go between each of the begin and end tags. What s important to notice at this point is the structure of the file and that the element names describe the content of the element, rather than its formatting. By labeling the content, you can apply content-based formatting using XSL.
The XML structure is strictly hierarchical. XML refers to the items in this hierarchy as XML nodes. Nodes have parent-child relationships that are identified using the XPath, as shown in Figure 13-14.
Figure 13-14. XML nodes
XML is well suited for structured data such as stock quotes, employee information, product inventory, order status, and other data that we re used to dealing with in an organized fashion. XML is not as well suited for information that uses creative or ad hoc organization.
Creating an XSL File
The XSL file provides the layout and logic that transforms data stored in the XML file into the output you see on the Web form. To create an XSL file in Visual Studio, choose Add New Item from the Project menu, choose XSLT File from the Templates list, and then click Open.
The XSL file contains template statements that select the items to import from the XML file. Each template includes standard HTML elements to apply formatting to the elements imported from the XML file. For example, the following XSL template converts cookbook title, subtitle, and introduction elements from an XML file to h1, h2, and p elements in HTML:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/cookbook"> <xsl:apply-templates select="cookbook" /> <h1><xsl:value-of select="title" /></h1> <h3><xsl:value-of select="subtitle" /></h3> <hr /> <p><xsl:value-of select="introduction" /></p> <hr /> <h2><xsl:text>Recipes</xsl:text></h2> <xsl:apply-templates select="recipe" /> </xsl:template> </xsl:stylesheet>
The preceding example uses the XSL elements and attributes summarized in Table 13-2.
Element | Attributes | Use to |
xsl:stylesheet | version | Identify the version of XSL being used. Version 1.0 is the current version at the time of this writing. |
xmlns:xsl | Specify the prefixes for elements in the XSL file. | |
xsl:template | match | Define a template for an XML node. |
xsl:apply-templates | select | Apply a template to the selected node. |
xsl:value-of | select | Retrieve the value of an XML node or evaluate an XPath expression. |
xsl:text | Include literal text or white space characters in the output. |
Figure 13-15 shows how these elements work to transform cookbook XML data through the XML server control.
Figure 13-15. Basic XSL elements in action
The XSL elements demonstrated in Figure 13-15 perform the minimum tasks for displaying data with XSL: they define a template, import data into that template, display values from the XML, and insert literal text. Those are all tasks that are more easily performed simply by using regular HTML and style sheets. However, using XSL offers two advantages:
You can change the position of the element (page layout) in the XSL file without having to change your data.
You can perform logical operations on data, such as looping and conditional processing.
These advantages are discussed in the following sections.
Changing Layout
You change page layout in XSL by moving elements in the XSL file. For example, the following XSL displays the cookbook XML in a two-column format and displays the subtitle before the title:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/cookbook"> <xsl:apply-templates select="cookbook" /> <table> <tr> <td width="300"> <h3><xsl:value-of select="subtitle" /> <xsl:text>...</xsl:text></h3> <h1><xsl:value-of select="title" /></h1> </td> <td width="500"> <xsl:text>recipe text goes here..</xsl:text> </td> </tr> <tr> <td width="300"> <hr /> <xsl:value-of select="introduction" /> <hr /> </td> <td width="500"> </td> </tr> </table> </xsl:template> </xsl:stylesheet>
Figure 13-16 shows the changes to the output on the Web form.
Figure 13-16. Changing layout with XSL
Including Other Templates
An XSL file can contain multiple templates. You define an XSL template for each XML node that is uniquely formatted. For example, the cookbook XML shown earlier in this lesson could be organized into four templates:
The main template formats the title and description of the book and provides a starting point. XSL execution starts with this template because it selects the root node (match="/ cookbook ).
The recipe template formats the recipes included in the book.
The ingredients template formats the list of ingredients.
The instructions template formats the steps that follow the list of ingredients.
Use the xsl:apply-templates element to apply a template to a node. For example, the following XSL applies the ingredient and instruction templates from the recipe template, which is in turn applied from the main template. The links between the templates are shown in boldface:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/cookbook"> <xsl:apply-templates select="cookbook" /> <h1><xsl:value-of select="title" /></h1> <h3><xsl:text>...</xsl:text><xsl:value-of select="subtitle" /></h3> <hr /> <p><xsl:value-of select="introduction" /></p> <hr /> <xsl:apply-templates select="recipe" /> </xsl:template> <xsl:template match="recipe"> <h3><xsl:value-of select="title" /></h3> <p><xsl:value-of select="description" /></p> <p><b><xsl:text>Serves: </xsl:text></b> <i><xsl:value-of select="servings" /></i></p> <xsl:apply-templates select="ingredients" /> <xsl:apply-templates select="instructions" /> </xsl:template> <xsl:template match="ingredients"> <ul> <li><xsl:value-of select="ingredient/name" /> <xsl:text> </xsl:text> <b><xsl:value-of select="ingredient/quantity" /></b></li> </ul> </xsl:template> <xsl:template match="instructions"> <p><xsl:value-of select="introduction" /></p> <ol> <li><xsl:value-of select="step" /></li> </ol> <p><xsl:value-of select="summary" /></p> </xsl:template> </xsl:stylesheet>
At run time, the preceding XSL template creates HTML output, as shown in Figure 13-17.
Figure 13-17. Using multiple templates together
But wait! There s only one ingredient (cooter) and one instruction (cut it up). As the templates are written, they process only one node each. To repeat tasks, you need to use the XSL looping elements, as described in the following section.
Repeating Tasks
To format repeating elements in an XML file, such as list or table items, use the xsl:for-each XSL element. The xls:for-each element selects the repeated node, and then the contained XSL is applied to each occurrence of that node, as shown here:
<xsl:for-each select="ingredient"> <xsl:value-of select="name" /><br /> </xsl:for-each>
The preceding XSL outputs the name of each repeated ingredient node. To refer to the repeated node itself, use the "." XPath identifier. For example, the following XSL outputs the text of each repeated step node in the XML:
<xsl:for-each select="step"> <xsl:value-of select="." /><br /> </xsl:for-each>
The following XSL uses the xsl:for-each element (shown in boldface) to display all of the recipes, ingredients, and steps in the cookbook:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/cookbook"> <xsl:apply-templates select="cookbook" /> <h1><xsl:value-of select="title" /></h1> <h3><xsl:text>...</xsl:text><xsl:value-of select="subtitle" /></h3> <hr /> <p><xsl:value-of select="introduction" /></p> <hr /> <xsl:for-each select="recipe"> <xsl:apply-templates select="." /> </xsl:for-each> </xsl:template> <xsl:template match="recipe"> <h3><xsl:value-of select="title" /></h3> <p><xsl:value-of select="description" /></p> <p><b><xsl:text>Serves: </xsl:text></b> <i><xsl:value-of select="servings" /></i></p> <xsl:apply-templates select="ingredients" /> <xsl:apply-templates select="instructions" /> </xsl:template> <xsl:template match="ingredients"> <ul> <xsl:for-each select="ingredient"> <li><xsl:value-of select="name" /> <xsl:text> </xsl:text> <b><xsl:value-of select="quantity" /></b></li> </xsl:for-each> </ul> </xsl:template> <xsl:template match="instructions"> <p><xsl:value-of select="introduction" /></p> <ol> <xsl:for-each select="step"> <li><xsl:value-of select="." /></li> </xsl:for-each> </ol> <p><xsl:value-of select="summary" /></p> </xsl:template> </xsl:stylesheet>
At run time, the preceding XSL formats the cookbook XML, as shown in Figure 13-18.
Figure 13-18. Formatting repeated elements
Inserting Hyperlinks and Other HTML Elements
Use xsl:element to compose HTML elements that contain attributes, such as hyperlinks, server controls, or HTML controls. For example, the following XSL creates a hyperlink that returns the user to the top of the page:
<xsl:element name="a"> <xsl:attribute name="name"> <xsl:text>#top</xsl:text> </xsl:attribute> <xsl:text>Return to top.</xsl:text> </xsl:element>
At run time, the preceding XSL generates the following output:
<a href="#top">Return to top.</a>
You can couple this XSL with the XPath generate-id function to automatically create a table of contents for your document that links to locations within a document, as shown in boldface in the following XSL:
<xsl:template match="/cookbook"> <h1><xsl:value-of select="title" /></h1> <h3><xsl:text>...</xsl:text><xsl:value-of select="subtitle" /></h3> <hr /> <p><xsl:value-of select="introduction" /></p> <hr /> <!-- Display table of contents --> <h4>Contents</h4> <xsl:apply-templates mode="contents" select="recipe" /> <xsl:for-each select="recipe"> <xsl:apply-templates select="." /> </xsl:for-each> </xsl:template> <xsl:template match="recipe"> <!-- Create location links --> <xsl:element name="a"> <xsl:attribute name="name"> <xsl:value-of select="generate-id(title)" /> </xsl:attribute> <h3><xsl:value-of select="title" /></h3> </xsl:element> <p><xsl:value-of select="description" /></p> <p><b><xsl:text>Serves: </xsl:text></b> <i><xsl:value-of select="servings" /></i></p> <xsl:apply-templates select="ingredients" /> <xsl:apply-templates select="instructions" /> </xsl:template> <xsl:template mode="contents" match="recipe"> <!-- Create table of contents links --> <xsl:element name="a"> <xsl:attribute name="href"> <xsl:text>#</xsl:text> <xsl:value-of select="generate-id(title)" /> </xsl:attribute> <xsl:value-of select="title" /> </xsl:element> <br /> </xsl:template>
At run time, the preceding XSL generates the output shown in Figure 13-19.
Figure 13-19. Generating a table of contents
The generate-id XPath function generates a unique ID for the XML node passed to it as an argument. The ID takes the form XSLTnodename#, where # is a 12-digit integer, as in this example: XSLTtitle120123120120.
Sorting Items
Use the xsl:sort element to sort items within another XSL element. For example, the following XSL sorts the table of contents created in the preceding section:
<h4>Contents</h4> <xsl:apply-templates mode="contents" select="recipe"> <xsl:sort select="title" order="ascending" /> </xsl:apply-templates>
The xsl:sort element can be included in xsl:apply-templates elements, as shown in the preceding code, or in xsl:for-each elements.
Performing Conditional Tasks
XSL includes two sets of elements for performing conditional tasks: use xsl:if to evaluate a single condition; use xsl:choose with contained xsl:when and xsl:otherwise elements to evaluate multiple conditions. Table 13-3 summarizes these conditional elements.
Element | Attribute | Use to |
xsl:if | test | Test a Boolean expression and process the contained elements if the result is true. |
xsl:choose | Test multiple conditions using contained xsl:when and xsl:otherwise elements. This is the equivalent of a Select Case (Visual Basic .NET) or switch (Visual C#) statement. | |
xsl:when | test | Test one Boolean expression within an xsl:choose element, and then process the contained item and exit the xsl:choose element if the result is true. This is the equivalent of the Case (Visual Basic .NET) or case (Visual C#) statement. |
xsl:otherwise | Process the contained item if none of the xsl:when elements within an xsl:choose element are true. This is the equivalent of the Case Else (Visual Basic .NET) or default (Visual C#) statement. |
The conditional elements test attribute evaluates an XPath expression to determine whether the XSL contained in the conditional element should be processed. For example, the following XSL creates a table of contents if there are more than four recipes in the cookbook:
<xsl:if test="count(recipe) > 4"> <h4>Contents</h4> <xsl:apply-templates mode="contents" select="recipe" /> </xsl:if>
The preceding XSL uses the XPath count function to return the number of recipe nodes in the cookbook. If the count is greater than 4, the Contents heading is output and the contents template is processed; otherwise, the contents are omitted.
Similarly, you can use XPath functions within xsl:choose elements to change output based on several conditions. For example, the following XSL inserts a line break after every four contents items; otherwise, it separates items with a tab space:
<xsl:template mode="contents" match="recipe"> <xsl:element name="a"> <xsl:attribute name="href"> <xsl:text>#</xsl:text> <xsl:value-of select="generate-id(title)" /> </xsl:attribute> <xsl:value-of select="title" /> </xsl:element> <xsl:choose> <xsl:when test="position() mod 4 = 0"> <br /> </xsl:when> <xsl:otherwise> <xsl:text> </xsl:text> </xsl:otherwise> </xsl:choose> </xsl:template>
The preceding XSL uses the XPath position function to return the position of the current node within the node s collection. It also uses the XPath mod operator to determine whether the current position is evenly divisible by four.
More Info
We ve only scratched the surface of what you can do with XSL here. XML, XSL, and XPath are all languages in their own right. This lesson gives you enough information to get started, but for a complete education, see the Microsoft XML SDK documentation included in the Visual Studio .NET online Help. Microsoft Press books that cover this subject include XML Step by Step, Second Edition, by Michael J. Young, and XML Programming (Core Reference), by R. Allen Wyke, Sultan Rehman, and Brad Leupen.