perfectxml.com
 Basic Search  Advanced Search   
Topics Resources Free Library Software XML News About Us
You are here: home »» Free Library »» Wrox Press » Professional ASP.NET 1.0 XML with C# Saturday, 13 October 2007

Page: 1   |   2   |   3   |   4   |   5   |   6        

Structure of an XSLT Style Sheet

Now that we have a glimpse of what XSLT style sheets can do, the next step is to examine the actual structure of a style sheet. Of course the subject of XSLT style sheets is enough to fill an entire book, so our objective in this chapter will be to provide what you need to know in order to use its features in ASP.NET applications.

 

 

XSLT is a Declarative, Rule-Based Language

Unlike procedural languages, which are executed in sequential order, XSLT is a declarative, rule-based language where the XSLT processor determines the execution sequence. Simply stated, we describe the rules (which can appear in any order), and the processor parses these rules and applies them to produce a corresponding output document.

 

XSLT is XML

An XSLT style sheet is an XML document. All the rules that specify the behavior of a style sheet are contained within XML elements belonging to the XSLT namespace.

 

The <stylesheet> Document Element

The document or root element of the style sheet is <stylesheet>. Like the XML declaration node, it contains a version attribute, which we will set to "1.0". Typically, the prefix xsl is used to reference the XSLT namespace http://www.w3.org/1999/XSL/Transform. Therefore, the declaration usually looks like this:

 

<?xml version="1.0" encoding="UTF-8"?>

 <xsl:stylesheet version="1.0"

      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

 </xsl:stylesheet>

 

However, in keeping with standard XML rules, the xsl prefix is merely the suggested prefix for the required namespace declaration. In fact, when we create an XSLT file in Visual Studio .NET, it declares the XSLT namespace as the default.

 

Creating a Style Sheet in VS.NET

Open Visual Studio .NET and select File | New | File, or just press Ctrl-N. The following dialog box appears:

 

 

With the General folder in the Categories pane selected, select the XSLT File icon in the Templates pane. Click the Open button, and it will create an empty solution with a style sheet containing just the opening declaration as shown:

 

 

As mentioned earlier, Visual Studio .NET declares http://www.w3.org/1999/XSL/Tranform as the default namespace. Although this is the default behavior for Visual Studio .NET and won't normally cause any problems, we will use the xsl prefix in our examples this chapter. Alter the code like so:

 

<?xml version="1.0" encoding="UTF-8"?>

 <xsl:stylesheet version="1.0"

                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

 </xsl:stylesheet>

 

Now save the file by selecting File | Save XSLTFile1.xslt as... and a file dialog box will appear. When prompted, enter the name transform-one.xslt. We will add content to this style sheet shortly.

 

Specifying the Output Type

As stated earlier, the output of a transformation can either be XML, HTML, plain text, or qualified names (the exotic sounding qname-but-not-ncname type). By default, the output is HTML. We can specify other output types by declaring an <output> element as a child of the <stylesheet> element with the appropriate method attribute set. For example, this is how we specify XML as the output type:

 

<xsl:output method="xml" />

 

Note that as a child of the <stylesheet> document element, this element is designated as a top-level element of the style sheet. Top level elements are immediate children of <stylesheet>.

 

Other attributes of this element control behavior such as whether to omit the XML declaration in the resulting document, or which version and encoding should be specified.

 

Defining Template Rules

Template rules are elements that describe how the XSLT processor should transform nodes that meet certain criteria in an XML document. We declare template rules by creating a top-level element named <template>, and specifying which node(s) it contains rules for using an appropriate XPath expression in its match attribute.

 

The Template Rule for the Root Node

It is good practice to always declare a template rule for the root node of the source document in your XSLT style sheets, and some XSLT processors will actually fail if it is not present. Below is the syntax for a template rule matching the root node:

 

<xsl:template match="/">

   <!-- Template rules go here -->

 </xsl:template>

 

Notice the XPath expression provided in the match attribute, which, as we learned in the previous chapter, identify the root node. The "/" character on its own is also the starting point for absolute location paths. Refer back to Chapter 4 if you need more information on XPath expressions and location paths.

 

Don't forget that <template> is a top-level element, which means it must always be an immediate child of <stylesheet>. We can define as many <template> elements as we need in a style sheet. What sets one template rule apart from another is the XPath expression in the match attribute, although we could have two templates with the same XPath expression, but differentiated by the mode attribute (covered in the Enhancing Template Rules section).

 

Specifying Template Rules for Other Nodes

The XPath expression in the match attribute of the <template> element identifies nodes in the source document that we wish to transform by applying that template. Let's illustrate this with the following XML document, which we've already seen in the previous chapter:

 

<?xml version="1.0" encoding="UTF-8" ?>

 <?custom-error code="0" message="OK" ?>

 <!--Shopping Cart Example-->

 <shopping-cart>

   <header>

     <customer id="P4LLC" billingId="001" shippingId="001" >

       <contact>Toshia Palermo</contact>

     </customer>

     <order-type>Regular</order-type>

   </header>

   <items>

     <item id="ITM-1001" productLine="1">

       <quantity>1</quantity>

       <list-price>123.45</list-price>

       <description>Gadget XYZ</description>

     </item>

     <item id="ITM-1002" productLine="1">

       <quantity>3</quantity>

       <list-price>4.00</list-price>

       <description>XYZ Accessory</description>

     </item>

     <item id="ITM-1003" productLine="2">

       <quantity>1</quantity>

       <list-price>15.00</list-price>

       <description>Gizmo Part</description>

     </item>

     <item id="ITM-1004" productLine="3">

       <quantity>1</quantity>

       <list-price>44.00</list-price>

       <description>Widget X</description>

     </item>

   </items>

 </shopping-cart>

 

This file, shopping-cart.xml, will be used in our examples throughout the chapter. The one difference with the file used in Chapter 4 is the absence of the namespace on the <shopping-cart> element, which has been removed for simplicity. The table below shows some example XPath expressions and their effect on the shopping-cart.xml document:

 

XPath Expression in match Attribute of <template> Element

Description

match="/shopping-cart"

This will match the <shopping-cart> element – the document element of the source XML. Remember that there can only ever be one document element in well- formed XML.

match="//item"

This matches any <item> elements in the source XML.

match="/*/items//@*"

This matches any attribute nodes that are descendants of the <items> element, which is itself a grandchild of the root node.

match="quantity"

This relative expression matches any <quantity> children of the context node.

 

Once the nodes are identified, the rules inside the <template> element describe the transformation to perform.

 

Accessing Values with <value-of>

Within the template, we can access each node matching the XPath expression as the context node. To obtain values from the source XML, we use the <value-of> element. It has an obligatory select attribute containing another XPath expression denoting the node whose value we want. The following example demonstrates this:

 

<xsl:template match="item">

   <div>

     Item=<xsl:value-of select="@id" />,    

      Quantity=<xsl:value-of select="quantity" />

   </div>

 </xsl:template>

 

 

The template rule in the above example matches <item> element children of the context node. Any such <item> element becomes in turn the context node for XPath expressions within the template. The first <xsl:value-of> element has a select attribute with an XPath expression locating the id attribute of the <item> element. The select attribute of the second <xsl:value-of> element provides a relative location path (with abbreviated syntax) to retrieve the value of the <quantity> child. These values are placed within an enclosing HTML <div>.

 

Earlier we indicated that the order in which template rules are defined is irrelevant, so how did the processor get to this template rule? The starting point is the template rule that matches the root node. From there, we can explicitly apply other templates to the elements we want to transform.

 

Applying Templates with <apply-templates>

The <apply-templates> element is used to transform nodes from within other templates. To apply transformations using the template in the previous example, we could use this element within the template for the root node, like so:

 

<xsl:template match="/">

   <html>

     <head>

       <title>Transformation Example</title>

     </head>

     <body>

       <xsl:apply-templates select="//item" />

     </body>

   </html>

 </xsl:template>

 

Here, we wrap the 'call' to the other template rule inside HTML markup, with the <apply- templates> element in the <body> tag. Our select attribute indicates that all of the <item> elements in the source XML document should be processed by any matching templates at this point. If we omit the select attribute, the parser would apply templates for all children of the context node.

 

The result of this call is similar to that produced by the SelectNodes method of the XmlNode object (or any of its descendants, such as XmlDocument). The XSLT processor builds a node-set in memory, and looks for a template rule that satisfies a match for each node. In our example, a node-list of four elements is generated, appearing in the set in the order in which they appear in the source document. The XSLT processor then processes each node one at a time by searching the style sheet for a matching template, such as this one:

 

<xsl:template match="item">

   <div>

     Item=<xsl:value-of select="@id" />,    

        Quantity=<xsl:value-of select="quantity" />

   </div>

 </xsl:template>

 

For the first <item> element in the document, this would produce the following output:

 

<div>Item=ITM-1001, Quantity=1</div>

 

The processor then moves on to the next node in the node-set, which in this case is also processed by the same template rule, and so on for each node in the node-set. The final output is this:

 

<div>Item=ITM-1001, Quantity=1</div>

<div>Item=ITM-1002, Quantity=3</div>

<div>Item=ITM-1003, Quantity=1</div>

<div>Item=ITM-1004, Quantity=1</div>

 

If we put all this together in the transform-one.xslt sheet, here is what it looks like in its entirety:

 

<?xml version="1.0" encoding="UTF-8" ?>

 

 <xsl:stylesheet version="1.0"

               xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

 

   <xsl:template match="/">

     <html>

       <head>

         <title>Transformation Example</title>

       </head>

       <body>

         <xsl:apply-templates select="//item" />

       </body>

     </html>

   </xsl:template>

 

 <xsl:template match="item">

     <div>

     Name=<xsl:value-of select="@id" />,

     Quantity=<xsl:value-of select="quantity" />

     </div>

   </xsl:template>

 </xsl:stylesheet>

 

It is also worthy of note that we have ignored all the other nodes in the source XML document. We only need to define template rules for those nodes we need to process.

Page: 1   |   2   |   3   |   4   |   5   |   6        

Next Page >>>        

  Contact Us |  | Site Guide | About PerfectXML | Advertise ©2004 perfectxml.com. All rights reserved. | Privacy