XSLT Transformations

only for RuBoard

As discussed in Chapter 3, XSLT can be used to transform a source XML document into a different result tree. This result tree can be a variety of XML formats, which makes XSLT such an exciting technology. The .NET classes used to perform the transformations are not concerned with the format of the output ”rather, they're concerned with performing the transformation.

You've already seen the XPathDocument object and examined using it with XPath queries. Recall that the XPathDocument object contains only one method specific to XML ”the CreateNavigator method. The real power behind the XPathDocument object is how it is instantiated : It can read over stream object implementations , such as MemoryStream and FileStream , reader implementations, such as XmlReader and TextReader , or accept a path to a file.

You can use the XPathDocument object to read XML data from one of these sources and then use this document as the source of the XML transformation.

Now let's walk through the XSLT stylesheet to confirm your understanding of it. Begin by creating the XSLT stylesheet node in the following code. The example XML file uses a namespace with a URI of urn:foo:bar , so add that namespace to the XSLT document as well. You can use a prefix of tns to distinguish the namespace URI from the xsl namespace prefix. You can also specify that the output method for this stylesheet is XML:

 <?xml version="1.0" encoding="UTF-8" ?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tns="urn:foo:bar">       <xsl:output method="xml"/>  .  .  .  </xsl:stylesheet> 

The next step: Add some template rules to the document. The first template rule matches the Customers element that has a namespace URI that matches the namespace URI associated with the prefix tns . It creates the root result element called DATA and then tells the parser to continue processing, as shown here:

 <xsl:template match="tns:Customers">       <xsl:element name="DATA">            <xsl:apply-templates />       </xsl:element>  </xsl:template> 

The second template rule matches the Customer element because it also has a namespace URI that matches the namespace URI associated with the tns prefix. It creates an element called Company with an ID attribute. The CompanyID attribute in the result tree receives the same value as the ID attribute in the source tree. It then tells the processor to continue processing the template rules using a specific set of nodes:

 <xsl:template match="tns:Customer">       <xsl:element name="Company">            <xsl:attribute name="CompanyID">                 <xsl:value-of select="@id"/>            </xsl:attribute>            <xsl:apply-templates select="tns:CompanyName"/>            <xsl:apply-templates select="tns:Contact"/>       </xsl:element>  </xsl:template> 

The final template rules to add both act the same way. They simply add attributes to the result document, like this:

 <xsl:template match="tns:CompanyName">       <xsl:attribute name="CompanyName">            <xsl:value-of select="."/>       </xsl:attribute>  </xsl:template>  <xsl:template match="tns:Contact">       <xsl:attribute name="FirstName">            <xsl:value-of select="tns:FirstName"/>       </xsl:attribute>       <xsl:attribute name="LastName">            <xsl:value-of select="tns:LastName"/>       </xsl:attribute>       <xsl:attribute name="Title">            <xsl:value-of select="tns:Title"/>       </xsl:attribute>  </xsl:template> 

The following output from this transformation contains the same data as the input tree, but with a different structure than the input document. The XSLT document and the results are shown here (the code to perform the transformation is explained in the next section):

 <?xml version="1.0" encoding="utf-8" ?>  <DATA>       <Company CompanyID="ALFKI" CompanyName="Alfreds Futterkiste"  FirstName="Maria" LastName="Anders" Title="Sales Representative"></Company>       <Company CompanyID="LOWES" CompanyName="Lowe's" FirstName="Keth"  LastName="Bunn" Title="Assistant Manager"></Company>       <Company CompanyID="VELVE" CompanyName="The Velvet Room"  FirstName="Rodney" LastName="Wade" Title="Bar Manager"></Company>       <Company CompanyID="GABST" CompanyName="Georgia's Best Pressure and  Stain" FirstName="Steve" LastName="Durling" Title="Owner"></Company>       <Company CompanyID="VBDNA" CompanyName="Kirk Allen Evans Consulting,  Inc." FirstName="Kirk Allen" LastName="Evans" Title="Owner"></Company>  </DATA> 

Now that your memory about template processing and the difference between input and result trees has been refreshed, take a closer look at the code that performs the transformations.

The XslTransform Class

The XslTransform class is specifically designed to perform XSLT transformations in .NET. It supports XSLT 1.0 and can be extended with the < msxsl :script> element or through custom XSLT extension functions (recall the discussion in Chapter 3 about the XSLT extension functions). It has two main methods worth noting: the Load and the Transform methods.

Using the Load Method of the XslTransform Class

The Load method of the XslTransform class loads a stylesheet into memory. The Load method supports a variety of data sources to load the stylesheet. It also accepts an XmlResolver class that can specify credentials for external resources (refer to the section, "Retrieving External Data" for a refresher on how to use the XmlResolver abstract class).

Table 6.12 shows the overloads for the Load method.

Table 6.12. Constructors for the XslTransform Class

Overloaded Load() Method

Description

Load(IXPathNavigable)

Loads the stylesheet contained in the object that implements the IXPathNavigable interface.

Load(string)

Loads the stylesheet located at the specified URL.

Load(XmlReader)

Loads the stylesheet contained in the specified XmlReader ( XmlTextReader or XmlNodeReader ).

Load(XPathNavigator)

Loads the stylesheet contained in the XPathNavigator .

Load(IXPathNavigable, XmlResolver)

Loads the stylesheet contained in the object that implements the IXPathNavigable interface. Resolves external resources by using the XmlResolver object specified.

Load(string, XmlResolver)

Loads the XSLT stylesheet located at the specified URL. Uses the XmlResolver object to resolve external resources.

Load(XmlReader,XmlResolver)

Loads the stylesheet contained in the specified XmlReader by using the XmlResolver to resolve external resources.

Load(XPathNavigator,XmlResolver)

Loads the stylesheet contained in the specified XPathNavigator by using the XmlResolver to resolve external resources.

Recall that the XmlNode object supports the IXPathNavigable interface so all nodes that inherit from XmlNode can be passed in as arguments to the Load method. This includes an XmlDocument object. You can also pass an XmlReader object, reading the entire contents of the reader into the XslTransform object.

Using the Transform Method of the XslTransform Class

Just as the Load method accepts multiple overloads, the Transform method also accepts multiple overloads. The simplest version of the overloaded transform accepts two string arguments: the path for the input XML document and the path for the output result document. You can, however, perform more complicated transformations by using a variety of sources. For example, it's been stated multiple times throughout this chapter that each XmlNode object also supports the IXPathNavigable interface. So, you can pass in an XmlDocument object to the Transform method and an XPathDocument object. Recall, however, that the XPathDocument object doesn't perform the same rule checking that the XmlDocument class does, so the XPathDocument is faster by an order of magnitude or more.

Listing 6.13 creates an XmlTextReader object based on an XML file and then creates an XPathDocument based on the reader's XML contents.

Listing 6.13 A Sample Transformation
 <%@ Page language="c#" Debug="true"%>  <%@ Import Namespace="System.Xml"%>  <%@ Import Namespace="System.Xml.XPath"%>  <%@ Import Namespace="System.Text"%>  <%@ Import Namespace="System.Xml.Xsl"%>  <script language="C#" runat="server">            private void Page_Load(object sender, System.EventArgs e)            {                XmlTextReader reader = new  XmlTextReader(Server.MapPath("sample.xml"));                 XPathDocument doc = new XPathDocument(reader);                 reader.Close();                 reader = new  XmlTextReader(Server.MapPath("sampletransform.xslt"));                 XslTransform transform = new XslTransform();                 transform.Load(reader);                 transform.Transform(doc,null,Response.OutputStream);                 reader.Close();            }  </script> 

Because the contents of the reader were already loaded into the XPathDocument , it's safe to close the reader and reload it with the XSLT stylesheet. The transform method is then called using the input file, with no argument list, and the contents are specified so that they're written to the Response object's content stream.

You have seen examples of loading all the object types and have used XmlResolver to add NetworkCredentials for a specified URI. These concepts are used later in this section. In Listing 6.13, you specified null for the XsltArgumentList parameter. But what if you want to pass a parameter to the stylesheet? Suppose, for example, that you want to sort your document based on the parameter that's passed in.

The XsltArgument Class

The XsltArgument class is predominately used to pass parameters to an XSLT stylesheet. As you saw in Chapter 3, it can also be used to add extension functions to the XSLT processor.

Listing 6.14 reconstructs the Pitchers.xml example XML document from Chapter 3.

Listing 6.14 Pitchers.xml
 <?xml version="1.0" encoding="utf-8" ?>  <PITCHERS>       <PITCHER>            <FNAME>John</FNAME>            <LNAME>Rocker</LNAME>            <TEAM>Indians</TEAM>            <CITY>Cleveland</CITY>            <ERA></ERA>       </PITCHER>       <PITCHER>            <FNAME>Tom</FNAME>            <LNAME>Glavine</LNAME>            <TEAM>Braves</TEAM>            <CITY>Atlanta</CITY>            <ERA></ERA>       </PITCHER>       <PITCHER>            <FNAME>Greg</FNAME>            <LNAME>Maddux</LNAME>            <TEAM>Braves</TEAM>            <CITY>Atlanta</CITY>            <ERA></ERA>       </PITCHER>       <PITCHER>            <FNAME>Randy</FNAME>            <LNAME>Johnson</LNAME>            <TEAM>Diamondbacks</TEAM>            <CITY>Arizona</CITY>            <ERA></ERA>       </PITCHER>  </PITCHERS> 

The stylesheet in Listing 6.15 is used to process the XML document.

Listing 6.15 Pitcherstyle.xslt
 <?xml version="1.0" encoding="UTF-8" ?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:param name="sortBy" select="'CITY'"/>  <xsl:template match="/">            <xsl:apply-templates/>       </xsl:template>       <xsl:template match="PITCHERS">            <TABLE border="1">                 <tr>                      <th><a onclick="javascript:SortData('FNAME');">First Name</a></th>                      <th><a onclick="javascript:SortData('LNAME');">Last Name</a></th>                      <th><a onclick="javascript:SortData('CITY');">City</a></th>                      <th><a onclick="javascript:SortData('TEAM');">Team</a></th>                      <th><a onclick="javascript:SortData('ERA');">ERA</a></th>                 </tr>                 <xsl:for-each select="PITCHER">  <xsl:sort select="*[name()=$sortBy]"/>  <tr>                           <td><xsl:value-of select="FNAME"/><br/></td>                           <td><xsl:value-of select="LNAME"/></td>                           <td><xsl:value-of select="CITY"/></td>                           <td><xsl:value-of select="TEAM"/></td>                           <td><xsl:value-of select="ERA"/></td>                                 </tr>                 </xsl:for-each>            </TABLE>       </xsl:template>  </xsl:stylesheet> 

You can use the sortBy parameter to specify the element that you want to sort on. The default is the CITY element, which occurs if no parameter is passed in. Otherwise, the value passed in is used. To pass the parameter to the stylesheet, use XsltArgumentList to add parameters that are passed to the stylesheet, as shown here:

 private void Page_Load(object sender, System.EventArgs e)            {                XmlTextReader reader = new  XmlTextReader(Server.MapPath("pitchers.xml"));                 XPathDocument doc = new XPathDocument(reader);                 reader.Close();                 reader = new  XmlTextReader(Server.MapPath("pitcherstyle.xslt"));                 XslTransform transform = new XslTransform();                 transform.Load(reader);  XsltArgumentList args = new XsltArgumentList();   args.AddParam("sortBy",string.Empty,"TEAM");   transform.Transform(doc,args,Response.OutputStream);   reader.Close();  } 

This example was slightly changed to include the XsltArgumentList object reference. You can add a parameter that's not associated with a specific namespace, and specify its value as the string TEAM . Then, you can pass the XsltArgumentList object to the Transform method to pass the parameters to the stylesheet, which causes the stylesheet to sort based on the TEAM element.

only for RuBoard


XML and ASP. NET
XML and ASP.NET
ISBN: B000H2MXOM
EAN: N/A
Year: 2005
Pages: 184

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net