XPath with XSLT

For many people, the whole idea behind XPath is to be able to use XSLT, so we'll take a look at XSLT in overview now. XSLT and XPath are natural to use together, and we'll see quite a few XSLT examples in this book. For that reason, we'll take a look at enough XSLT here to get started. You won't have to know how XSLT works in detailyou'll just have to know how things work in overview, and what XSLT templates do. We'll see XSLT examples that use XPath in Chapters 3 and 4. And Chapter 5 is dedicated to XSLT and XPath.

For more information, you can find

  • The W3C XSLT 1.0 recommendation at http://www.w3.org/TR/xslt

  • The current XSLT 2.0 specification at http://www.w3.org/TR/xslt20/

XSLT centers around the stylesheets that XSLT processors (such as the one in Internet Explorer) can use to transform XML documents into HTML, other XML documents, plain text, and so on. You can assign XPath expressions to the match and select attributes in XSLT elementsbut note that while the select attribute can handle any XPath expression, the match attribute can only handle XPath expressions that use the child or attribute axes.

As you might expect, XSLT stylesheets must be well- formed XML documents, so you start a stylesheet with the XML declaration. Next, you use a <stylesheet> element; by convention, XSLT stylesheets use the namespace xsl , which is "http://www.w3.org/1999/XSL/Transform". You must also include the version attribute in the <stylesheet> element; here, we'll use version 1.0:

 
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     .     .     . 

Creating a Template

That's how you start an XSLT stylesheet. To work with specific nodes in an XML document, XSLT is a programming language that uses templates . When you match or select nodes, a template tells the XSLT processor how to transform the node for output. For example, say that you want to replace the root node with a whole new HTML document. You can start by creating a template with the <xsl:template> element, setting the match attribute to the XPath expression for the root node, "/" :

 
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:template match="/">   .   .   .   </xsl:template>  </xsl:stylesheet> 

When the root node is matched, the template is applied to that node. In this example, we'll replace the root node with an HTML document, so we'll just include that HTML document directly as the content of the <xsl:template> element, as you see in Listing 1.3.

Listing 1.3 A Sample XSLT Document That Replaces the Root Node ( ch01_03.xsl )
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:template match="/">  <HTML>   <HEAD>   <TITLE>   A Transformation Example   </TITLE>   </HEAD>   <BODY>   This entire document has been replaced!.   </BODY>   </HTML>  </xsl:template> </xsl:stylesheet> 

And that's all it takes; by using the <xsl:template> element, we've set up a rule in the stylesheet. When the XSLT processor reads the document, the first node it sees is the root node. This rule matches that root node, so the XSLT processor replaces it with the HTML document, producing this result:

 
 <HTML>     <HEAD>         <TITLE>             A trivial transformation         </TITLE>     </HEAD>     <BODY>         This transformation has replaced         the entire document.     </BODY> </HTML> 

That's our first, rudimentary transformation. All we've done is to replace the entire document with another one. But of course, that's just the beginning of the power you have using XSLT and XPath.

The xsl:apply-templates Element

The template used in the preceding section only applied to one nodethe root node, and performed a trivial action, replacing the entire XML document with an HTML document. However, you can also apply templates to the children of a node that you've matched, and you do that with the <xsl:apply-templates> element.

For example, say that you want to convert ch01_01.xml to HTML. The document element in that document is <planets> , so we can match that element with a template, setting the match attribute to the name of the element we want to match, and then replace the <planets> element with an <HTML> element, like this:

 
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:template match="planets">   <HTML>   .   .   .   </HTML>   </xsl:template>  .     .     . </xsl:stylesheet> 

But what about the children of the <planets> element? To make sure they are transformed correctly, you use the <xsl:apply-templates> element this way:

 
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:template match="planets">         <HTML>  <xsl:apply-templates/>  </HTML>     </xsl:template>     .     .     . </xsl:stylesheet> 

Now you can provide templates for the child nodes. In this case, we'll just replace each of the three <planet> elements with some text, which we place directly into the template for the <planet> element as you see in Listing 1.4.

Listing 1.4 A Sample XSLT Document That Replaces <planet> Elements with Text ( ch01_04.xsl )
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:template match="planets">         <HTML>             <xsl:apply-templates/>         </HTML>   </xsl:template>  <xsl:template match="planet">   <P>   Placeholder text for planet data...   </P>   </xsl:template>  </xsl:stylesheet> 

And that's itnow the <planets> element is replaced by an <HTML> element, and the <planet> elements are also replaced:

 
 <HTML>     <P>         Placeholder text for planet data...     </P>     <P>         Placeholder text for planet data...     </P>     <P>         Placeholder text for planet data...     </P> </HTML> 

You can see that this transformation works, but it's still less than useful; all we've done is to replace the <planet> elements with some text. What if we wanted to access some of the data in the <planet> element? For example, say that we wanted to place the text from the <name> element in each <planet> element in the output document:

 
 <planet>  <name>Mercury</name>  <mass units="(Earth = 1)">.0553</mass>     <day units="days">58.65</day>     <radius units="miles">1516</radius>     <density units="(Earth = 1)">.983</density>     <distance units="million miles">43.4</distance><!--At perihelion--> </planet> 

To gain access to this kind of data, you can use the select attribute of the <xsl:value-of> element.

Getting the Value of Nodes with xsl:value-of

In this example, we'll extract the name of each planet and insert that name into the output document. To get the name of each planet, we'll use the <xsl:value-of> element in a template targeted at the <planet> element, and select the <name> element with the select attribute as you can see in Listing 1.5.

Listing 1.5 A Sample XSLT Document That Uses the Names of <planet> Elements ( ch01_05.xsl )
 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:template match="planets">         <HTML>             <UL>             <LI><xsl:apply-templates/></LI>             </UL>         </HTML>     </xsl:template>     <xsl:template match="planet">  <xsl:value-of select="name"/>  </xsl:template> </xsl:stylesheet> 

Applying the stylesheet ch01_05.xsl , the <xsl:value-of select="name"/> element directs the XSLT processor to insert the name of each planet into the output document, and so the results look like this:

 
 <HTML>     <UL>         <LI>Mercury</LI>         <LI>Venus</LI>         <LI>Earth</LI>     </UL> </HTML> 

How do you run XSLT examples like this? You might not think you have an XSLT processor handy, but you do if you have Internet Explorer. To connect an XSLT stylesheet to an XML document in Internet Explorer, you use the href attribute of a <?xml-stylesheet?> XML processing instruction as you see in ch01_06.xml (Listing 1.6). In that example, we're connecting our sample XML document to the XSLT stylesheet ch01_05.xsl .

Listing 1.6 A Sample XML Document for Internet Explorer ( ch01_06.xml )
 <?xml version="1.0"?>  <?xml-stylesheet type="text/xsl" href="ch01_05.xsl"?>  <planets>     <planet>         <name>Mercury</name>         <mass units="(Earth = 1)">.0553</mass>         <day units="days">58.65</day>         <radius units="miles">1516</radius>         <density units="(Earth = 1)">.983</density>         <distance units="million miles">43.4</distance><!--At perihelion-->     </planet>     <planet>         <name>Venus</name>         <mass units="(Earth = 1)">.815</mass>         <day units="days">116.75</day>         <radius units="miles">3716</radius>         <density units="(Earth = 1)">.943</density>         <distance units="million miles">66.8</distance><!--At perihelion-->     </planet>     <planet>         <name>Earth</name>         <mass units="(Earth = 1)">1</mass>         <day units="days">1</day>         <radius units="miles">2107</radius>         <density units="(Earth = 1)">1</density>         <distance units="million miles">128.4</distance><!--At perihelion-->     </planet> </planets> 

And that's all it takesnow you can run XSLT examples using XPath in Internet Explorer.

Working with Attributes

What if you wanted to use XSLT and XPath to display not only the value of each of the <name> , <mass> , and <radius> elements, but also the units for each value, such as "miles" for the <radius> element? We can recover the units from each element by getting the value of the units attribute of that elementyou can see what we're aiming for in Figure 1.8, where the results are displayed in an HTML table.

Figure 1.8. Displaying planetary data and units.

graphics/01fig08.jpg

To create this result, we've got to use more than just the <xsl:value-of select="name"/> type of elements we've been using up to now, because we want to display the units for each measurement as well. We can start by creating the HTML for the table you see in Figure 1.8, matching the <planets> element and applying templates for the children of this element:

 
 <xsl:template match="/planets">     <HTML>         <HEAD>             <TITLE>                 The Planets Table             </TITLE>         </HEAD>         <BODY>             <H1>                 The Planets Table             </H1>             <TABLE BORDER="2">                 <TR>                     <TD>Name</TD>                     <TD>Mass</TD>                     <TD>Radius</TD>                     <TD>Day</TD>                 </TR>  <xsl:apply-templates/>  </TABLE>         </BODY>     </HTML> </xsl:template> 

Next, we match each <planet> element and invoke a new template on each element that has units we need to display:

 
 <xsl:template match="planet">     <TR>        <TD><xsl:value-of select="name"/></TD>  <TD><xsl:apply-templates select="mass"/></TD>   <TD><xsl:apply-templates select="radius"/></TD>   <TD><xsl:apply-templates select="day"/></TD>  </TR> </xsl:template> 

In each of these additional templates, such as the one for the <mass> element, we want to get both the value of the element and its units. To refer to the current element, we can use "." , which refers to the context node:

 
 <xsl:template match="mass">  <xsl:value-of select="."/>  .     .     . </xsl:template> 

This recovers the value of the current element. Next, we insert a space, using the <xsl:text> element like this:

 
 <xsl:template match="mass">     <xsl:value-of select="."/>  <xsl:text> </xsl:text>  .     .     . </xsl:template> 

Finally, we get the value of the units attribute for the <mass> element, which displays the units for the element's value (the <xsl:text> element lets us insert whitespace as needed heremore on that in Chapter 5) :

 
 <xsl:template match="mass">     <xsl:value-of select="."/>     <xsl:text> </xsl:text>  <xsl:value-of select="@units"/>  </xsl:template> 

And that's all it takesyou can see the final XSLT stylesheet, ch01_07.xsl , in Listing 1.7.

Listing 1.7 Accessing Attributes in a Stylesheet ( ch01_07.xsl )
 <?xml version="1.0"?> <xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <!-- This template matches all planets elements -->     <xsl:template match="/planets">         <HTML>             <HEAD>                 <TITLE>                     The Planets Table                 </TITLE>             </HEAD>             <BODY>                 <H1>                     The Planets Table                 </H1>                 <TABLE BORDER="2">                     <TR>                         <TD>Name</TD>                         <TD>Mass</TD>                         <TD>Radius</TD>                         <TD>Day</TD>                     </TR>                     <xsl:apply-templates/>                 </TABLE>             </BODY>         </HTML>     </xsl:template>     <xsl:template match="planet">        <TR>           <TD><xsl:value-of select="name"/></TD>           <TD><xsl:apply-templates select="mass"/></TD>           <TD><xsl:apply-templates select="radius"/></TD>           <TD><xsl:apply-templates select="day"/></TD>        </TR>    </xsl:template>     <xsl:template match="mass">         <xsl:value-of select="."/>         <xsl:text> </xsl:text>         <xsl:value-of select="@units"/>     </xsl:template>     <xsl:template match="radius">         <xsl:value-of select="."/>         <xsl:text> </xsl:text>         <xsl:value-of select="@units"/>     </xsl:template>     <xsl:template match="day">         <xsl:value-of select="."/>         <xsl:text> </xsl:text>         <xsl:value-of select="@units"/>     </xsl:template> </xsl:stylesheet> 

And you can see the results in Figure 1.8. That covers the XSLT in overview that we'll use for our XPath exampleyou won't need an in-depth knowledge of XSLT here, but an acquaintance will help because our XPath examples will sometimes use XSLT.



XPath. Navigating XML with XPath 1.0 and 2.0 Kick Start
XPath Kick Start: Navigating XML with XPath 1.0 and 2.0
ISBN: 0672324113
EAN: 2147483647
Year: 2002
Pages: 131

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