Hack 63. Use Client-Side XPath
Use XPath to enhance your XSL transformations.
XPath defines a syntax for selecting parts of an XML document. It consists of syntax to select direct elements and their attributes, as well as a set of standard functions. XPath was released as a W3C recommendation in 1999 and is such a major element of XSL that without it, you will not be able to make XSL documents. This hack serves to dirty your hands with basic XPath syntax.
XPath syntax is a superset of the standard patterns that are used to apply templates to XML elements using the match attribute of the xsl:template element. Patterns allow you to say which nodes you do and do not wish to match for a transformation. Basic patterns allow you to match nodes by element name, child elements, descendants, and attributes. The XPath superset allows matching on much more powerful expressions. These expressions can be used in any XSL element that allows a select attribute. Currently, that means these tags: xsl:apply-templates, xsl:value-of, xsl:for-each, xsl:copy-of, xsl:variable, xsl:param, and xsl:sort.
In addition to being able to select a list of element nodes, XPath is able to produce Booleans, numbers, and strings.
The power of XPath lies in its ability to match on all the basic match pattern tests, as well as on ancestor, parent, sibling, preceding, and following nodes. Without the XPath capabilities of XSL, performing anything other than simple operations on XML would be impossible.
6.7.1. Use Criteria to Select an XML Nodeset
<?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="projects.xsl"?> <mozilla-projects> <project version="1.0" downloads="5305002">Firefox</project> <project version="0.9" downloads="176083">Thunderbird</project> <project version="0.8">Camino</project> <project version="2.16" downloads="2731227">Bugzilla</project> <project version="0.2">Sunbird</project> </mozilla-projects>
When performing XSL transformations, it is common to want to select only a certain set of nodes from those available. To restrict the node set, we need to apply a condition to limit the nodes returned. We can apply an expression in a select attribute between two square brackets after the node name is specified.
To display all projects with a version number higher than one, we can use the following template:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <head><title>Mozilla Projects</title></head> <body> <h1>Mozilla Projects</h1> <ol> <xsl:apply-templates select="mozilla-projects/project[@version >= 1]"> <xsl:sort select="." /> </xsl:apply-templates> </ol> </body> </html> </xsl:template> <xsl:template match="project"> <li><xsl:value-of select="." /></li> </xsl:template> </xsl:stylesheet>
As you can see, we are selecting all project elements that are children of the mozilla-projects node. In addition to this, we are applying the condition to this set of elements that they must have an attribute (represented by the @ symbol) that is greater than (represented by > because the standard greater-than sign is the same as a closing element symbol) or equal to 1. Figure 6-5 shows the output.
Figure 6-5. HTML elements matched by a simple XPath
6.7.2. Use XPath to Expose Expression Axes
Sometimes, you need to reference other parts of an XML document than the current node and its attributes. Using node axes, you are able to select different parts of the tree relative to the context node (i.e., to the current node). Some of the axes you can experiment with include ancestor, attribute, child, descendant, following, parent, and self.
To demonstrate this, we will apply templates when we find a particular attribute. Once the template is applied to the attribute, we would still like to reference the element value. We can access this value using the parent axes. Note that we have also maintained alphabetical sorting on the project names by using the extended syntax for parent in the xsl:sort element.
If we want to see all those projects that have a download count attribute, we can change the template document to read:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <head><title>Mozilla Projects</title></head> <body> <h1>Mozilla Projects</h1> <ol> <xsl:apply-templates select="mozilla-projects/project/@downloads"> <xsl:sort select="parent::project" /> </xsl:apply-templates> </ol> </body> </html> </xsl:template> <xsl:template match="@downloads"> <li><xsl:value-of select="parent::project" /></li> </xsl:template> </xsl:stylesheet>
Figure 6-6 shows that this alternate set of transformations changes the output without changing the original XML-based content.
Figure 6-6. Alternate HTML output made with XPath syntax
Although this hack covers only a small amount of the XPath expression syntax, you can already see the powerful results it can produce. You can view the full XPath standard at http://www.w3.org/TR/xpath.