The Foundation: XML, XSL, X-Link (2/4) - exploring XML
The Pattern MatcherLet's dissect the example style sheet of my last column to explain the three elements:
<xsl:template match="/">This tells the XSL processor to apply the subsequent template (not shown here) when it finds a match to the match argument, in this case the document root. The match argument needs to be specified in XPath syntax, a related W3C specification for referencing parts of an XML document. It bears strong resemblance to directory path specifications, with some odd additions:
<xsl:template match="shoppingcart/item">This example matches a item tag enclosed by a shoppingcart tag, anywhere in a document tree.
<xsl:template match="/shoppingcart/item">(Note the leading slash before shoppingcart). This example matches the same construct as above, but only at the top level of the document, directly underneath the document root.
<xsl:template match="price[@unit='USD']">This checks for an attribute named unit on the element price with a value of 'USD.' It would not match a price of any other currency.
Here are some more examples, with increasing obscurity:
- * matches any element
- @* matches any attribute
- @class matches any class attribute (not any element that has a class attribute)
- chapter|appendix matches any chapter element and any appendix element
- appendix//para matches any para element with an appendix ancestor element
- text() matches any text node
- id("me") matches the element with unique ID me
- para matches any para element that is the first para child element of its parent
- *[position()=1 and self::para] matches any para element that is the first child element of its parent
- para[last()=1] matches any para element that is the only para child element of its parent
- items/item[position()>1] matches any item element that has a items parent and that is not the first item child of its parent
- item[position() mod 2 = 1] would be true for any item element that is an odd-numbered item child of its parent.
- div[@class="appendix"]//p matches any p element with a div ancestor element that has a class attribute with value appendix
The rules engineThe rules engine needs to resolve conflicts when more than one pattern matches to decide which one takes precedence. A complete discussion of precedence rules is beyond the scope of this arcticle, but two rules of thumb are handy to remember:
- A more specific match takes precedence over a less specific one, so in case of an item in a shoppingcart "shoppingcart/item" takes precedence over "item."
- In the case of multiple included and embedded style sheets, the latest, innermost definition takes precedence
The template processorThe template processor executes a set of instructions in consequence to a pattern match. These instructions create new elements in the output tree, either implicitly by using non-XSL content like
<HTML> <HEAD> <TITLE>Your shopping cart</TITLE> ...or explicitly using <xsl:element>, <xsl:attribute>, or <xsl:text>. XSL instructions like
<xsl:for-each select="shoppingcart/item">allow you to iterate over a list of nodes,
<xsl:apply-templates>hands over control to the pattern matcher again, to search for the next rule to be fired. More examples and detail will follow in later installments of this column.
Created: Dec. 20, 1999
Revised: Dec. 21, 1999