Navigating using XPath

Navigation in the content node tree is done using xpath features. XPath is language for navigating and addressing parts of an xml document. All nodes can be addressing using xpath syntax, some construct gets really long and hard to read, but it is quite effective once you get the hang of it.

Lets look at an example from the Umbraco RunwayTopNavigation.xslt: 

 

Example

...
<xsl:for-each select="$currentPage/ancestor-or-self::node [@level=$level]/node [string(data [@alias='umbracoNaviHide']) != '1']">
...

This line describes that we iterate over a set of nodes specified by an xpath expression.  To descipher the XPath lets take it bit by bit. Generally you read the expression from left to right, continously keeping track of what nodeset we are are working with. 

$currentPage
We start out with the current context page node $currentPage - this is our bases. Note that "node" in the expression is actually an element called "node"
/ancestor-or-self::node
From here we find any ancestor node-element as well as our current node (self)
[@level=$level]
We filter all found nodes by defining that we only want the nodes that are on the right level. @level is an attribute of all node-elements holding the level of the node, meaning the level of descend from the root. $level is a variable holding our fixed level number.
node [string(data [@alias='umbracoNaviHide']) != '1']
From here we take all "node"-children with a data-child of our nodeset (all "node"-elements in Umbraco holds a data-child node) where the @alias attribute called "umbracoNaviHide" (which is how custom properties of the document type are referred to) is not set to true (i.e. equals "1")

The result is a set of nodes at a specified level which are not hidden.

 

What's the deal with the []-predicates ?

Often you see one or more [expr]-parts being used in XPath expressions. These are really interesting, because they are powerfull to us, not least when using xslt in Umbraco. When interpreting XPath expressions we normally navigate around the content tree using siblings, descendent and other node-navigating terms. Once we find the right type of node, we sometimes want to filter them based on specific tests on attribute values or similar. This is exactly what we use the [] for. The [expr] is called a predicate, and the predicate expression always evaluates to true or false, where true values indicates accepted predicate. In the above example we had [@level=$level] - this evaluates to true only when the @level attribute equals our $level attribute. Multiple predicates can be applied in the same expression - also for the same nodes, which is really useful when accessing document properties.

Say you want to iterate over all children of the current node and filter them on some specific document property, instead of do a for-each on all children and then inside do an if-statement testing for the specific document property you can do like this:

<xsl:for-each select="$currentPage/node/data [@alias = 'mySpecialProperty'][string(.) != '']">

In this case we want to use data-nodes with @alias = 'mySpecialProperty' - which is how content properties are referenced. Since the content of this data-node element is the mySpecialProperty-property value and we want to test on that we convert it to a string ( string(.) ) and test if it is empty - a simple test in this case.

 

 XPath, unabbreviated syntax

Here are a few samples from the w3c xpath site:

Here are some examples from the w3c-site of XPath expressions using the unabbreviated syntax:

child::para  selects the para element children of the context node
child::* selects  all element children of the context node
child::text()  selects all text node children of the context node
child::node()  selects all the children of the context node, whatever their node type
attribute::name  selects the name attribute of the context node
attribute::*  selects all the attributes of the context node
descendant::para  selects the para element descendants of the context node
ancestor::div  selects all div ancestors of the context node
ancestor-or-self::div  selects the div ancestors of the context node and, if the context node is a div element, the context node as well
descendant-or-self::para  selects the para element descendants of the context node and, if the context node is a para element, the context node as well
self::para  selects the context node if it is a para element, and otherwise selects nothing
child::chapter/descendant::para  selects the para element descendants of the chapter element children of the context node
child::*/child::para  selects all para grandchildren of the context node
selects the document root (which is always the parent of the document element)
/descendant::para  selects all the para elements in the same document as the context node
/descendant::olist/child::item  selects all the item elements that have an olist parent and that are in the same document as the context node
child::para[position()=1]  selects the first para child of the context node
child::para[position()=last()]  selects the last para child of the context node
child::para[position()=last()-1]  selects the last but one para child of the context node
child::para[position()>1]  selects all the para children of the context node other than the first para child of the context node
following-sibling::chapter[position()=1]  selects the next chapter sibling of the context node
preceding-sibling::chapter[position()=1]  selects the previous chapter sibling of the context node
/descendant::figure[position()=42]  selects the forty-second figure element in the document
/child::doc/child::chapter[position()=5]/child::section[position()=2]  selects the second section of the fifth chapter of the doc document element
child::para[attribute::type="warning"]  selects all para children of the context node that have a type attribute with value warning 
child::para[attribute::type='warning'][position()=5]  selects the fifth para child of the context node that has a type attribute with value warning 
child::para[position()=5][attribute::type="warning"]  selects the fifth para child of the context node if that child has a type attribute with value warning 
child::chapter[child::title='Introduction']  selects the chapter children of the context node that have one or more title children with string-value equal to Introduction 
child::chapter[child::title]  selects the chapter children of the context node that have one or more title children
child::*[self::chapter or self::appendix]  selects the chapter and appendix children of the context node
child::*[self::chapter or self::appendix][position()=last()] selects the last chapter or appendix child of the context node

 

XPath, abbreviated syntax

Here are some examples from w3c of location paths using abbreviated syntax: 

para  selects the para element children of the context node
selects all element children of the context node
text()  selects all text node children of the context node
@name  selects the name attribute of the context node
@*  selects all the attributes of the context node
para[1]  selects the first para child of the context node
para[last()]  selects the last para child of the context node
*/para  selects all para grandchildren of the context node
/doc/chapter[5]/section[2]  selects the second section of the fifth chapter of the doc 
chapter//para  selects the para element descendants of the chapter element children of the context node
//para  selects all the para descendants of the document root and thus selects all para elements in the same document as the context node
//olist/item  selects all the item elements in the same document as the context node that have an olist parent
selects the context node
.//para  selects the para element descendants of the context node
..  selects the parent of the context node
../@lang  selects the lang attribute of the parent of the context node
para[@type="warning"]  selects all para children of the context node that have a type attribute with value warning 
para[@type="warning"][5]  selects the fifth para child of the context node that has a type attribute with value warning 
para[5][@type="warning"]  selects the fifth para child of the context node if that child has a type attribute with value warning 
chapter[title="Introduction"]  selects the chapter children of the context node that have one or more title children with string-value equal to Introduction 
chapter[title]  selects the chapter children of the context node that have one or more title children
employee[@secretary and @assistant]  selects all the employee children of the context node that have both a secretary attribute and an assistant attribute

 

 


Comments:

2. februar 2010:

Great

Commented by: jd