9. Navigation

During the explanation of the element <value-of>, it was explained that when elements are outside of the direct context, these elements can still be selected by making use of the forward slash. This specific use of the forward slash follows the rules speficied for the XPath language. The select attribute of <value-of> or <for-eache> contain what are called XPath expressions.

XPath is a language which enables us to navigate to different points in the XML Document. The language is maintained by W3C. XPath represents the XML document as a collection of nodes, and all of these nodes can be reached by making use of special symbols.

Symbol Description

/

The forward slash is used to navigate to elements which are outside of the context. The context is typically determined by the element mentioned in the match attribute of <template> or in the select attribute of <for-each>. Within this context, you can refer to the direct children of this element without any further measures. If you want to refer to their subelements, however, you need to work with forward slashes.

Example:
<value-of select="collection/body/letter" />

Using the forward slash at the beginning of an XPath expression means that the path that follows departs from the root node.

//

The double forwards slashes can be used if you want to retrieve a certain element, regardless of where it appears in the hierarchy of the XML tree. If the two slashes are followed by the name of an element, this expression will return all the elements that can be reached from that context, even if they are are on different levels.

Example:
<value-of select="//letter" />

If the command above is used in a <template/> element with a match pointing towards collection, this command will still select the first <letter> element, even though <letter> is not a direct child of <collection/>. These two forward slashes can be very useful when you don't know beforehand where exactly a given element appears. In many XML schemata, including TEI, elements can occur on many different hierarchical levels.

@

The 'at' is used to navigate to the value of an attribute. This symbol needs to be combined with the name of the attribute whose value you want to select.
Example:
<value-of select="collection/body/letter/language/@code" />

The <language> element has an attribute named <code>. If you want to display this language code (i.e. the value of the <code> element), you need to refer to <@code> in your XPath expression.

.

The full stop is used to refer to the highest element in the context that has been established. This symbol can be used, for example, in a <xsl:for-each> element.

Example:
<xsl:for-each select="annotations/note">
<xsl:value-of select=".">
</xsl:for-each>

In between the opening and the closing tags of <for-each>, a specific 'context' is established. The focus of the XSLT parser is temporarily on a specific section of the XML source document. In this fragment, the focus is on the element <note>. You have seen that you refer to the direct children of <for-each>. But what if you want to refer to this <for-each> element itself? To refer to the element which establishes the context, you work with the dot ('.'). The fragment above firstly navigates across all the <note> element, using <for-each>. The <value-of> elements within <for-each> also displays the contents of these notes.

[]

Following a path specified in the @select attribute of <xsl:for-each>, you can add a set of square brackets.
Within these square brackets, you can specify a criterion, similar to the type of criterion that you can give in the @test attribute of <xsl:if>

Example:
<xsl:for-each select="letter[ year &lt; 1900 ]">
<xsl:value-of select="sender">
</xsl:for-each>

The code in this example only selects the letters with the specific property. It only selects the letters written before 1900. Such square brackets can also be used in combination with the count() function (see below).

In section 7 of this tutorial, it was explained that you select an element conditionally by working with the <if > element. The conditions that you provide in the <test> attribute are also XPath expressions. You can work with a number of symbols to formulate conditions.

&gt;

Greater than

&lt;

Less than

=

Equal to

!=

Not equal to

Note that the symbol for "greater than" and for "less than" is an XML entity. We cannot use the characters "<" and ">" themselves, because otherwise a parser might confuse these with the symbols that start of end XML elements.

When you want to compare the contents of an element with a a string (i.e. a text fragment), you need to include this string (or search term) within quotes. If the full XPath expression given in the <test> attribute is surrounded by double quotes, the string needs to be given in single quotes.

Using such conditions, you can filter the result of the transformation very effectively. To select the authors of all the letters written after 1870, for example, you can work with the following XSLT code:

<xsl:for-each select="letter">

<xsl:if test="year &gt; 1870">
<xsl:value-of select="author" />
</xsl:if>

</xsl:for-each>

You can also combine criteria using and. The fragments below selects the letters written in English after 1870.

<xsl:for-each select="letter">

<xsl:if test="year &gt; 1870 and language/@code = 'eng' ">
<xsl:value-of select="author" />
</xsl:if>

</xsl:for-each>

Finally, XPath also provides a number of functions. You can use these functions the change the appearnaces of texts or to produce quantitative data about the XML source document.

Function Description

normalize-space()

XML documents may contain white space. This term refers to spaces, tabs and line breaks. When you refer to specific elements (in <value-of>, for instance), these spaces, tabs or line breaks may be selected as well. To remove all leading and trailing white space in the element you want to select, you can work with normalize-space().

Example:
<value-of select="normalize-space(author)"/>

In this example, all the spaces preceding or followng the text in the <author> element will be removed.

count()

This function produces data about the number of elements on a specific location in the XML source document.

Example:
<value-of select="count( collection/body/letter ) "/>

The command above produces a single number, indicating the number of <letter> elements in the document. In other words, it counts the number of letters in the collection.

contains()

This function can be used in conditions in the <if> element. The equals sign ('=', see above) looks at the full textual contents of a element. In some cases, you may also want to check if an element contains a given substring. The contains() function demands two values: (1) the name of the element you want to search in, and (2) the search term.

Example:
<if test ="contains( author , "Sijthoff" ) " >

This XPath expression is true if the contents of the author element contains the substring given as a second value. This specific expression can select all the people whose name contains the substring 'Sijthoff'.

position()

When, using <xsl:for-each>, you navigate across multiple items on the same hierarchical level in an XML document, you can request information about the sequence number of this item using position(). You can use this function, for example, to generate line numbers in a poem.

Example:
<xsl:for-each select="line">
<xsl:value-of select="position()" />
<xsl:text>. </xsl:text>
<xsl:value-of select="." />
</xsl:for-each>

last()

This function always returns the position (i.e. the sequence number) of the last item in the context that is set. When you use last() within a loop begun by <xsl:for-each>, this function gives information about the number of iterations: the number of times the code within the body of <xsl:for-each> is repeated.

Make exercise 6