The Xml Path (XPath) lanuage provides syntax to reference components of an XML document by their hierarchical address. This form of address is similar to the composition of a URL.
In XPath the hierarchy begins with the XML document itself, which is referenced in XPath with the "/" forward slash character. Below that comes the root XML element, followed by nested child elements. This means that any element can be referenced by stating its absolute XPath address from the document level. Fo instance, /root/child/grandchild references an element whose parent is a direct child of the root XML element.
Each path of an XPath address is known as a "node", where "/" is the "document node", referencing the XML document itself, and the "root node" references the root XML element.
XPath expressions can be used in XSL stylesheets to select elements by their absolute path address, and to select elements by their relative address - such as parents and siblings. They can also be used to reference the attribute value of a selected element.
Alternatively, as XPath considers child elements to be indexed by position (starting at 1) an element can be referenced by its index value. For instance, the first child of the root element can be referenced as /root/child[1], the second child as /root/child[2], the third child as /root/child[3], and so on.
XPath supports comparison operators to test for equality, inequality, and greater or lesser values, so that an element can be selected according to the result of a comparitive test. It also supports arithmetic operators that enable calculations to be performed with selected values.
Additionally the XPath language provides a number of ucntions that can manipulate selected string and numeric values.
All examples in here demonstrate how to use Xpath expressions by creating various XSL stylesheets for the XML document listed below. (click here)
<?xml version = "1.0" encoding = "UTF-8" ?>
<?xml-stylesheet type = "text/xsl" href = "to_be_replaced.xsl" ?>
<bike:doc
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.auxy.com/xsd bikes.xsd"
xmlns:bike = "http://www.auxy.com/xsd">
<bike:item id = "electraglide">
<bike:make>Harley Davidson</bike:make>
<bike:model>Electra Glide</bike:model>
<bike:ltr>1.584</bike:ltr>
<bike:cyl>2</bike:cyl>
<bike:drive>belt</bike:drive>
<bike:price>16095</bike:price>
</bike:item>
<bike:item id = "goldwing">
<bike:make>Honda</bike:make>
<bike:model>Gold Wing</bike:model>
<bike:ltr>1.832</bike:ltr>
<bike:cyl>6</bike:cyl>
<bike:drive>shaft</bike:drive>
<bike:price>19299</bike:price>
</bike:item>
<bike:item id = "r1200rt">
<bike:make>BMW</bike:make>
<bike:model>R 1200 RT</bike:model>
<bike:ltr>1.170</bike:ltr>
<bike:cyl>2</bike:cyl>
<bike:drive>shaft</bike:drive>
<bike:price>17075</bike:price>
</bike:item>
</bike:doc>
With XPath an XSL stylesheet can select child elements using their absolute path address, in much the same way that files can be addressed in a file structure. For instance, on a Windows file system C:\dir\file is the absolute path address of file in a directory dir that is a child of the C: drive. Similarly, in XPath /doc/item is the absolute path address of an item element whose parent doc is a child of the / document .
Having selected a particular element its child elements can be addressed using "./" dot-slash synatx, which selects the level below the current location. For instance, with an element having an absolute XPath address of /doc/item/make where /doc/item has been selected as the current location ./make can be used to address teh child make element.
<?xml version = "1.0" encoding = "UTF-8" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:b = "http://www.auxy.com/xsd" >
<xsl:output method = "html" encoding = "UTF-8" />
<xsl:template match = "/">
<html> <head> <title>XSL Output</title> </head>
<body>
<table style = "width:450px">
<tr> <th>Make</th> <th>Model</th> <th>Liters</th> <th>Cyls</th> <th>$</th> </tr>
<xsl:for-each select = "/b:doc/b:item">
<tr style = "background:lime;text-align:center">
<td> <xsl:value-of select = "./b:make" /> </td>
<td> <xsl:value-of select = "./b:model" /> </td>
<td> <xsl:value-of select = "./b:ltr" /> </td>
<td> <xsl:value-of select = "./b:cyl" /> </td>
<td> <xsl:value-of select = "./b:price" /> </td>
</tr>
</xsl:for-each>
</table></body> </html>
</xsl:template>
</xsl:stylesheet>
Unlike the XPath "./" dot-slash syntax in the previous example, that addresses the level below the current location, "../" addresses teh level above the current location. This can be used to address the parent element and siblings, such as ../brother . Additionally the attribute value of a parent can be addressed, such as ../@id .
Let's create an XSL stylesheet that is associated with an entire XML document and selects the sibling of a particular element, along with the attribute value of its parent:
<?xml version = "1.0" encoding = "UTF-8" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:b = "http://www.auxy.com/xsd" >
<xsl:output method = "html" encoding = "UTF-8" />
<xsl:template match = "/">
<html>
<head> <title>XSL Output</title> </head>
<body>
<table style = "width:450px">
<tr style = "background:thistle;text-align:center">
<xsl:for-each select = "/b:doc/b:item/b:make">
<td>
<xsl:value-of select="." /><br/>
<xsl:value-of select="../b:model" /> <br/>
<img>
<xsl:attribute name="src" >
<xsl:value-of select= "concat( ../@id, '.jpg' ) " />
</xsl:attribute>
</img>
</td>
</xsl:for-each>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Selecting nodes by position
XPath regards child elements as a one-based array - where the first child element has an array index number of 1. Each element can be addressed by its index position, such as /doc/item[3]. Additionally the final element in a child array can be selected using the XPath last() function
Follow these steps to create an XSL stylesheet that is associated with an entire XML document and selects two child elements by their position with the XML document:
<?xml version = "1.0" encoding = "UTF-8" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:b = "http://www.auxy.com/xsd" >
<xsl:output method = "html" encoding = "UTF-8" />
<xsl:template match = "/">
<html> <head> <title>XSL Output</title> </head>
<body>
<div style = "background:yellow">
<xsl:for-each select = "/b:doc/b:item[2]">
<xsl:value-of select = "./b:make" /> <br/>
<xsl:value-of select = "./b:model" /> <br/>
$ <xsl:value-of select = "./b:price" />
</xsl:for-each>
</div>
<div style = "background:aqua">
<xsl:for-each select = "/b:doc/b:item" >
<xsl:if test = "position() = last()" >
<xsl:value-of select = "./b:make" /> <br/>
<xsl:value-of select = "./b:model" /> <br/>
$ <xsl:value-of select = "./b:price" />
</xsl:if>
</xsl:for-each>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
XPath can compare values in a test expression using the operators = (is equal to), and != (is not equal to), < (less than), and > (greater than). Additionally the and boolean operator can test if two conditions are both met, and the or boolean operator can test if either of two conditions are met.
Follow these steps to create an XSL stylesheet that is associated with an entire XML document and selects sibling elements after comparing the selected element's value:
<?xml version = "1.0" encoding = "UTF-8" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:b = "http://www.auxy.com/xsd" >
<xsl:output method = "html" encoding = "UTF-8" />
<xsl:template match = "/">
<html> <head> <title>XSL Output</title> </head>
<body>
<xsl:for-each select = "/b:doc/b:item/b:ltr" >
<xsl:if test = ". > 1.5" >
<div style = "margin:5px;background:orange">
Make: <xsl:value-of select = "../b:make" /> <br/>
Model: <xsl:value-of select = "../b:model" /> <br/>
Liters: <xsl:value-of select = "." /> </div>
</xsl:if>
</xsl:for-each>
<xsl:for-each select = "/b:doc/b:item/b:cyl" >
<xsl:if test = ". < 6" >
<div style = "margin:5px;background:lime">
Make: <xsl:value-of select = "../b:make" /> <br/>
Model: <xsl:value-of select = "../b:model" /> <br/>
Cylinders: <xsl:value-of select = "." /> </div>
</xsl:if>
</xsl:for-each>
</body> </html>
</xsl:template>
</xsl:stylesheet>
XPath can perform arithmetic operations, using these operators:
| Operator | Operation | Example |
| + | Addition | 48 + 16 = 64 |
| - | Subtraction | 48 - 16 = 32 |
| * | Multiplication | 4 * 16 = 64 |
| div | Division | 64 div 4 = 16 |
Additionally XSL has a count function, which can count the number of instances of an element in an <xsl:for-each> element, and a sum function that can total a number of element values.
Lets create an XSL stylesheet that is associated with an entire XML document, counting the number of <item> elements and totalling the sume of <price> elements:
<?xml version = "1.0" encoding = "UTF-8" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:b = "http://www.auxy.com/xsd" >
<xsl:output method = "html" encoding = "UTF-8" />
<xsl:template match = "/">
<html> <head> <title>XSL Output</title> </head>
<body>
<xsl:for-each select = "/b:doc/b:item">
<div style = "background:pink; padding:3px">
<xsl:value-of select = "concat( ./b:make , ' ')" />
<xsl:value-of select = "concat( ./b:model, ' ' )" />
Price: $ <xsl:value-of select = "./b:price" /> </div>
</xsl:for-each>
<div style = "background:red;color:white; font-weight:bold; padding:3px">
Sum Total Price Of All <xsl:value-of select = "count(/b:doc/b:item)"/>
Bikes is $ <xsl:value-of select = "sum(/b:doc/b:item/b:price)"/>
</div>
</body> </html>
</xsl:template>
</xsl:stylesheet>
XPath provides a useful format-number function that formats a selected numerical value according to a specified pattern. For instance, format-number(.'$ ##,###.##') specifies a typical currency pattern for the current selection. Similarly, the ceiling, floor and round functions can be used to format decimals into a near integer value before they are output.
Let's create an XSL stylesheet that is associated with an entire XML document and formats selected values:
<?xml version = "1.0" encoding = "UTF-8" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:b = "http://www.auxy.com/xsd" >
<xsl:output method = "html" encoding = "UTF-8" />
<xsl:template match = "/">
<html> <head> <title>XSL Output</title> </head>
<body>
<table style = "width:450px; background:wheat">
<tr style="background:olive; color:yellow"> <th>Model</th>
<th>Regular Price</th> <th>10% Discount</th> <th>Sale Price</th></tr>
<xsl:for-each select = "/b:doc/b:item/b:price">
<tr>
<td>
<xsl:value-of select = "../b:model" />
</td>
<td>
<xsl:value-of select = "format-number(., '$ ##,###')" />
</td>
<td style="color:red; font-weight:bold">
Save <xsl:value-of select = "format-number( (. div 100)*10, '$ #,###')"/>
</td>
<td style="background:red; color:white; font-weight:bold">
<xsl:value-of select = "format-number( floor(. - (. div 100)*10), '$ ##,###')"/>
</td>
</tr>
</xsl:for-each>
</table>
</body> </html>
</xsl:template>
</xsl:stylesheet>
XPath has substring-before and substring-after functions that are useful to extract part of a selected string value. These require two arguments stating a selected string value and where in that string the extraction should occur. For instance, the function call substring-after("Gold Wing", "Gold") extracts "Wing".
Strings can be manipulated to change their case using the XPath function translate(string, chageTheseletters, toTheseLetters). Typically the second and third arguments will specify the complete alphabet in lowercase and uppercase. As this can become unwieldy it is common to assign the alphabets to <xsl:variable> elements. These must each have a name attribute which can be referenced, using a "$" prefix, to specify them as arguments.
Let's create an XSL stylesheet that is associated with an entire XML document, assigning substrings and alphabets to <xsl:variable> elements and manipulating case in output:
<?xml version = "1.0" encoding = "UTF-8" ?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:b = "http://www.auxy.com/xsd" >
<xsl:output method = "html" encoding = "UTF-8" />
<xsl:template match = "/">
<html> <head> <title>XSL Output</title> </head>
<body>
<!-- Short model name variables. -->
<xsl:variable name = "g">
<xsl:value-of select =
"substring-after( /b:doc/b:item[1]/b:model, 'Electra ' )"/>
</xsl:variable>
<xsl:variable name = "w">
<xsl:value-of select =
"substring-after( /b:doc/b:item[2]/b:model, 'Gold ' )" />
</xsl:variable>
<!-- Case conversion variables. -->
<xsl:variable name="lc">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="uc">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<h2 style="color:tomato">
<xsl:value-of select="translate($g, $lc, $uc)"/>
versus
<xsl:value-of select="translate($w, $lc, $uc)"/>
</h2>
<p>
The <xsl:value-of select="$g"/> and the <xsl:value-of select="$w"/> are both great bikes. Some say the <xsl:value-of select="$w"/> is faster and smoother, but riding the <xsl:value-of select="$g"/> is a feeling that's something in your soul.
</p>
</body> </html>
</xsl:template>
</xsl:stylesheet>