Chapter 5 - XPath Espresso | |
XSLT For Dummies | |
by Richard Wagner | |
Hungry Minds 2002 |
The axis part of a location step is all about defining relationships between the current node and the nodes that you wish to select. There are 13 possible axes, which are listed in Table 5-1. Some of these axes can be abbreviated; these abbreviations are shown in the Shortened Syntax column.
In addition to defining relationships, the axis also specifies the direction from the current node that the processor walks the tree to gather up nodes. Normally, tree walking goes top-to-bottom, left-to-right , much like you read a page in this book. However, certain axes ancestor , ancestor-or-self , preceding , and preceding-sibling travel in reverse order. (When working with attribute and namespace axes, the nodes are always unordered.) For example, when processing a match pattern with a descendant axis, the XSLT processor starts with the first descendant defined in the source tree encountered and works its way downward until it reaches the last descendant for the current node. Or, when evaluating a preceding axis, the processor starts with the node just before the current node and works its way to the top of the document tree in reverse order. This directionality becomes important when you start thinking about the position of nodes within the node set that the axis returns. (I discuss node set positions later in this chapter.) Child axisOf the 13 available axes, the child axis is certainly the most common among them. It is used to select all the child nodes of the current node. The children are ordered based on the sequence in the document tree, as shown in Figure 5-3. Figure 5-3: Nodes selected by the child axis. For example, consider the following XML document shown in Listing 5-1, which is an XMLized version of this books table of contents. Listing 5-1: xsltfordummies-toc.xml <!-- xsltfordummies-toc.xml --> <book title="XSLT For Dummies"> <introduction/> <part number="I" name ="Getting Started With XSLT"> <chapter number="1"> <title>Introducing The X-Team</title> <summary>Introduce core XML/XSLT concepts</summary> </chapter> <chapter number="2"> <title>Writing Your First XSLT Stylesheet</title> <summary>Getting feet wet with a simple, practical example of transforming</summary> </chapter> </part> <part number="II" name ="Becoming An XSLT Transformer"> <chapter number="3"> <title>Transforming With Style (Stylesheets, that is)</title> <summary>Cover topics related to top level "domain": the XSL Stylesheet</summary> </chapter> <chapter number="4"> <title>Templates Rule!</title> <summary>Cover the second level domain: templates</summary> </chapter> <chapter number="5"> <title>XPath Espresso</title> <summary>Focus on the third level domain: XPath Expressions</summary> </chapter> <chapter number="6"> <title>We Want Results!</title> <summary>Provide practical examples to apply what was learned in Chapter 3-5</summary> </chapter> </part> <part number="III" name ="Prime Time XSLT"> <chapter number="7"> <title>Adding Programming Logic Isn't Just For Propheads</title> <summary>Add logic to template rules</summary> </chapter> <chapter number="8"> <title>Variables in XSLT: A Breed Apart</title> <summary>Add variables/parameters to template rules</summary> </chapter> <chapter number="9"> <title>Tweaking The Results To Get What You Want</title> <summary>Perform advanced data-related output options</summary> </chapter> <chapter number="10"> <title>To HTML And Beyond!</title> <summary>Output to HTML and other formats</summary> </chapter> <chapter number="11"> <title>Xpath Data Types and Functions</title> <summary>Cover practical examples of using built-in functions</summary> </chapter> </part> <part number="IV" name ="Extreme XSLT"> <chapter number="12"> <title>Combining XSLT Stylesheets</title> <summary>Using import and include</summary> </chapter> <chapter number="13"> <title>"Gimme Some Space" And Other Output Issues</title> <summary>Perform advanced output options</summary> </chapter> <chapter number="14"> <title>Keys and Cross-Referencing</title> <summary>Covers key and id usage</summary> </chapter> <chapter number="15"> <title>Namespaces Revisited</title> <summary>More about namespaces</summary> </chapter> <chapter number="16"> <title>Extending XSLT</title> <summary>Extensions for additional customization and power</summary> </chapter> <chapter number="17"> <title>Debugging XSLT Transformations</title> <summary></summary> </chapter> </part> <part number="V" name ="Part of Tens"> <chapter number="18"> <title> Ten Most Confusing Things About XSLT </title> </chapter> <chapter number="19"> <title>Ten All-Pro XSLT Resources On The Web</title> </chapter> <chapter number="20"> <title>Ten XSLT Processors Available Online</title> </chapter> </part> <appendix number="A" name="Glossary"/> </book> Suppose you wanted to output a quick list of the book chapters. To do so, you could set up a template rule like this: <xsl:template match="child::chapter"> <xsl:apply-templates select="child::title"/> </xsl:template> Using the child axis as the starting point, the match pattern for the template looks for all chapter nodes that are children of the current node. For the returning node set, the template uses the xsl:apply-templates instruction, but does so by defining a select attribute to narrow the output to the child title elements of the returning node set. The output is: Introducing The X-Team Writing Your First XSLT Stylesheet Transforming With Style (Stylesheets, That Is) Templates Rule! XPath Espresso We Want Results! Adding Programming Logic Isn't Just For Propheads Variables in XSLT: A Breed Apart Tweaking The Results To Get What You Want To HTML and Beyond! XPath Data Types and Functions Combining XSLT Stylesheets Gimme Some Space and Other Output Issues Keys and Cross-Referencing Namespaces Revisited Extending XSLT Debugging XSLT Transformations Ten Most Confusing Things About XSLT Ten All-Pro XSLT Resources On The Web Ten XSLT Processors Available Online Remember The location paths used inside the template of the template rule, such as in the select attributes of the xsl:apply-templates or xsl:value-of instructions , act off the returning node set, not the original document tree. Therefore, the current node of these select patterns is not the same as the current node of the template rules match pattern. You may find this fact surprising, but all the examples you have seen so far in this book have used the child axis. So why have you not seen child:: before now? That is because child is the default axis for a location step, so that if you do not explicitly define an axis value, the child axis becomes the implicit axis. Therefore, if I drop child:: from the template, I get an identical result: <xsl:template match="chapter"> <xsl:apply-templates select="title"/> </xsl:template> Attribute axisThe second most common axis type is attribute . The attribute axis selects all attributes of the current node. Like child:: , attribute:: has a shorter alternative, the @ symbol. Therefore, the following two are equivalent: <xsl:value-of select="attribute::id"/> and <xsl:value-of select="@id"/> If youre like me and routinely frequent Starbucks, I suspect you too picked up the coffee lingo from the baristas. I have a favorite drink I order nearly every time I go to my local shop. I first start off by saying, Id like a grande caf mocha with half of the chocolate syrup, nonfat milk, and extra whipped cream. But over time, I learned barista-speak. Now I say, I want a grande light, nonfat, extra whipped mocha. Both are a mouthful, but the second one is quicker rolling off the tongue. In the same way, XPath has some abbreviated ways to write axes values that make it quicker to write XPath expressions. These include:
Suppose, for example, you want to output a list of the book parts from the XML document shown in Listing 5-1. To do so, you set up a template rule like this: <xsl:template match="part"> Part <xsl:value-of select="@number"/>: <xsl:value-of select="@name"/> </xsl:template> Using the child axis as the starting point, the match pattern for the template looks for all part nodes that are children of the current node. The template uses xsl:value-of elements to output the number and name attributes of all returned part nodes as strings. The output is: Part I: Getting Started With XSLT Part II: Becoming An XSLT Transformer Part III: Prime Time XSLT Part IV: Extreme XSLT Part V: Part of Tens Parent axisThe parent axis specifies the parent of the current node (see Figure 5-4). Unlike most of the other axes, parent always refers to a single node, because a node never has two nodes as its immediate parent. Figure 5-4: Node selected by the parent axis. The parent axis is commonly abbreviated as .. (double periods) when it is used in combination with the node test node() . (I dont want to get ahead of myself because I talk about node tests in the next part of the chapter, but understanding this point can help you as you find out about axes.) node() is a node test that matches any node whatever kind it is. So, parent::node() means, "Dont worry about its node type; just give me the parent of the current node." (Similarly, child::node() selects all the children of the current node no matter their node type.) To illustrate the parent axis in action, suppose you want to transform xsltfordummies-toc.xml (shown in Listing 5-1) into a result document that looks like the following: Chapter 1, "Introducing The X-Team", is in Part I Chapter 2, "Writing Your First XSLT Stylesheet", is in Part I Chapter 3, "Transforming With Style (Stylesheets, That Is)", is in Part II Chapter 4, "Templates Rule!", is in Part II Chapter 5, "XPath Espresso", is in Part II Chapter 6, "We Want Results!", is in Part II Chapter 7, "Adding Programming Logic Isn't Just For Propheads", is in Part III Chapter 8, "Variables in XSLT: A Breed Apart", is in Part III Chapter 9, "Tweaking The Results To Get What You Want", is in Part III Chapter 10, "To HTML and Beyond!", is in Part III Chapter 11, "XPath Data Types and Functions", is in Part III Chapter 12, "Combining XSLT Stylesheets", is in Part IV Chapter 13, "Gimme Some Space and Other Output Issues", is in Part IV Chapter 14, "Keys And Cross-Referencing", is in Part IV Chapter 15, "Namespaces Revisited", is in Part IV Chapter 16, "Extending XSLT", is in Part IV Chapter 17, "Debugging XSLT Transformations", is in Part IV Chapter 18, "Ten Most Confusing Things About XSLT ", is in Part V Chapter 19, "Ten All-Pro XSLT Resources On The Web", is in Part V Chapter 20, "Ten XSLT Processors Available Online", is in Part V To get this output, you can create a template rule that looks like this: <xsl:template match="chapter"> Chapter <xsl:value-of select="@number"/>, "<xsl:value-of select="title"/>", is in Part <xsl:value-of select="../@number"/> </xsl:template> This template rule returns the chapter elements using match="chapter" . Inside the template, literal text is mixed with the following three xsl:value-of elements to get the resulting text:
Self axisYou use the self axis to select the current node, as shown in Figure 5-5. Figure 5-5: Node selected by the self axis. When used with the node() node test, self::node() is abbreviated as . (a single period), which in effect says, "Return the current node." For example, from Listing 5-1, to get the value of the introduction element and output it to a string, you can create a template rule like the following: <xsl:template match="isbn"> <xsl:value-of select="."/> </xsl:template> The match pattern returns the isbn element and the select="." uses the returned node itself in the xsl:value-of conversion. The end result is: 3651-6 Preceding-sibling and following-sibling axesThe preceding-sibling and following-sibling axes are used to select sibling nodes that come either before or after the current node (see Figures 5-6 and 5-7). Although the terms themselves are singular, preceding-sibling and following-sibling select all sibling nodes in the direction that is specified, not just the next or previous sibling. Figure 5-6: Nodes selected by the preceding-sibling axis. Figure 5-7: Nodes selected by the following-sibling axis. For example, consider the following XML snippet: <part number="II" name ="Becoming An XSLT Transformer"> <chapter number="3"> <title>Transforming With Style (Stylesheets, that is)</title> </chapter> <chapter number="4"> <title>Templates Rule!</title> </chapter> <chapter number="5"> <title>XPath Espresso</title> </chapter> <chapter number="6"> <title>We Want Results!</title> </chapter> </part> Suppose your context node is the <chapter number="5"> element and you want to get the value of the title element under <chapter number="6"> . To do so, you start out by using following-sibling::chapter to get the next siblings and then a second location step that retrieves the title element children: <xsl:template match="chapter[@number='5']"> <xsl:value-of select="following-sibling::chapter/title"/> </xsl:template> See the section, Using Predicates to Get Specific, later in the chapter for a more detailed example of preceding-sibling and following-sibling . Preceding and following axesThe preceding and following axes have a broader focus than do preceding-sibling and following-sibling . They return all the nodes, regardless of their hierarchy level, in the specified direction. preceding selects all the nodes before the current node on the tree, and following selects all the nodes after the current node. Figures 5-8 and 5-9 show these axes and their direction. Figure 5-8: Nodes selected by the preceding axis. Figure 5-9: Nodes selected by the following axis. Descendant and descendant-or-self axesThe descendant axis selects all the nodes under the current node, whether they are children, grandchildren, great-grandchildren, and so on (see Figure 5-10). The descendant-or-self axis selects both the current node and all its descendants (see Figure 5-11). The descendant-or-self axis can be useful when youre uncertain of the number of levels between two nodes or if you simply want to bypass the intermediate levels. Figure 5-10: Nodes selected by the descendant axis. Figure 5-11: Nodes selected by the descendant-or-self axis Ancestor and ancestor-or-self axesThe ancestor axis selects all the ancestors of the current node, and the ancestor-or-self axis selects both the current node plus all its ancestors. See Figures 5-12 and 5-13. Both axes are useful when you know a node is the current node or is above the current node in the document tree, but are not certain where. Figure 5-12: Nodes selected by the ancestor axis. Figure 5-13: Nodes selected by the ancestor-or-self axis. Namespace axisThe namespace axis selects all namespaces relevant for the current node.
|