Stay on the XPath

Boost your success with these 5 tips for using XPath in XSLT

Experiment with using XPath in the five tips in this article. Discover surprising facts about binary logic, and learn how the XPath position() function's value changes depending on its context. Another tip shows how to use XPath to select the first element of a given name. Finally, learn how to debug one of the most common and difficult defects.

Doug Domeny, Senior Software Engineer, Freelance

Doug Domeny has developed a browser-based, multilingual, business user-friendly XML editor written using XSLT, W3C XML Schema, DHTML, JavaScript, jQuery, regular expressions, and CSS. Holding a bachelor's degree in computer science and mathematics from Gordon College in Wenham, MA, Doug has served for many years on OASIS technical committees such as XML Localization Interchange File Format (XLIFF) and Open Architecture for XML Authoring and Localization (OAXAL). In his roles as a software engineer, he has developed significant skills in software engineering and architecture, UI design, and technical writing.



24 May 2011

Also available in Chinese Japanese

This article offers five tips—derived from real-world applications for which hours were spent digging deep into confusing and unexpected behaviors of XPath—for using XPath in your work:

  • False is sometimes true.
  • The XPath expressions (x != y) and not(x = y) are different and give different results.
  • The value of the XPath position() function changes depending on its context.
  • Select the first element of a given name with XPath.
  • Debug XPath select expressions that fail because of default namespaces.

With these tips, you can spare yourself hours of frustration.

Frequently used acronyms

  • API: Application programming interface
  • W3C: World Wide Web Consortium
  • XHTML: Extensible Hypertext Markup Language
  • XML: Extensible Markup Language
  • XSLT: Extensible Stylesheet Language Transformations

Tip 1: False is sometimes true

A string whose length is greater than zero is always evaluated as True when resolved to a Boolean function, even if its value is the string 'false'.

In an XPath expression, comparing a string and a Boolean function can yield unexpected results. To avoid trouble, do not compare a string to the built-in Boolean functions true() and false(). Instead, compare strings to the string values 'true' and 'false'. Keeping the Boolean functions true() and false() as Booleans without having them unintentionally converted to strings is difficult. A non-empty string is considered True even if its value is 'false'; therefore, boolean('false') = true() and boolean('true') = true(). Only an empty string ('') is False—namely, boolean('') = false().

Consider the unexpected result when a Boolean function is converted to a string and back again. First, the Boolean is converted to a string (for example, string(false()) = 'false'). When converted back, as in boolean(string(false())), the result is true().

The string() function, however, is not the only means of converting a Boolean function to a string. Result tree fragments (RTF)—which are sometimes unavoidable—are strings. For example, consider Listing 1, which is an XML document of documents with their name, year of publication, and number of pages.

Listing 1. XML source document
<Documents>
  <Document id="18396">
    <Name>Knowing the Good</Name>
    <Year>2010</Year>
    <Pages>35</Pages>
  </Document>
  <Document id="18397">
    <Name>Beyond Standards: Best Practices</Name>
    <Year>2011</Year>
    <Pages>12</Pages>
  </Document>
  <Document id="18398">
    <Name>101 Ways to Do the Same Thing</Name>
    <Year>2011</Year>
    <Pages>50</Pages>
  </Document>
</Documents>

Listing 2 is an XSLT template that searches for recent documents with at least 20 pages. Unfortunately, this template produces incorrect results.

Listing 2. Erroneous XSLT template
<xsl:template match="Document">
  <xsl:variable name="recentFullLengthPublications">
    <xsl:choose>
      <xsl:when test="Year=2011 and Pages &gt;= 20">
        <xsl:value-of select="true()"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="false()"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:if test="$recentFullLengthPublications">
    <xsl:copy-of select="Name"/>
  </xsl:if>
</xsl:template>

The transformation returns the XML in Listing 3, which is incorrect. Only one element should be returned—namely, "101 Ways to Do the Same Thing." All three elements, however, are returned.

Listing 3. Incorrect results
<Name>Knowing the Good</Name>
<Name>Beyond Standards: Best Practices</Name>
<Name>101 Ways to Do the Same Thing</Name>

Result tree fragment (XSLT 1.0)

A transformation expressed in XSLT describes rules for transforming a source tree into a result tree. A template is instantiated for a particular source element to create part of the result tree. When a template is instantiated, each instruction is executed and replaced by the RTF that it creates. A variable might be bound to an RTF. An RTF is treated equivalently to a node set that contains a single root node; however, operations are permitted on an RTF only if that operation would be permitted on a string. (Excerpts are from "XSL Transformations (XSLT) Version 1.0." See Resources for a link.)

The document named "101 Ways to Do the Same Thing" is the only document in 2011 with at least 20 pages, so what went wrong? Content of a variable produces an RTF. This fragment is evaluated as a string, even if its value was a Boolean function.

The test expression in <xsl:if test="$recentFullLengthPublications"> from Listing 2 is incorrect. The test is always True; all <Name> elements in the source document are returned. Even the test expression in <xsl:if test="$recentFullLengthPublications=true()"> is incorrect. The variable $recentFullLengthPublications is going to be either the string 'true' or 'false', not a Boolean data type. Therefore, the statement <xsl:if test="$recentFullLengthPublications='true'">does work.

The template, however, is confusing because it uses the true() and false() functions, which are misleading in this case. The template in Listing 4 is both correct and more readable. It uses 'yes' and 'no' instead of 'true' and 'false' to avoid the association with Boolean types. Remember to enclose 'yes' and 'no' in single quotation marks.

Listing 4. Correct XSLT template
<xsl:template match="Document">
  <xsl:variable name="recentFullLengthPublications">
    <xsl:choose>
      <xsl:when test="Year=2011 and Pages &gt;= 20">
        <xsl:value-of select="'yes'"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="'no'"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:if test="$recentFullLengthPublications='yes'">
    <xsl:copy-of select="Name"/>
  </xsl:if>
</xsl:template>

Beware the Boolean functions true() and false(). In this simple example, the variable is not necessary and, even if used, could have been defined with a select attribute. The result with a select attribute is not automatically converted to a string; as such, a Boolean value remains a Boolean. The select attribute does not return an RTF.

Often, a condition is too complex for the select attribute, and you must define a variable as an RTF. For this simple example, either of the templates in Listing 5 and Listing 6 are preferred. In Listing 5, the test does not need to compare to a string because the variable returns a Boolean type rather than an RTF as a result of the select attribute.

Listing 5. Improved simple XSLT template
<xsl:template match="Document">
  <xsl:variable name="recentFullLengthPublications" 
        select="Year=2011 and Pages &gt;= 20" />
  <xsl:if test="$recentFullLengthPublications">
    <xsl:copy-of select="Name"/>
  </xsl:if>
</xsl:template>

Alternatively, you can drop the variable, as in Listing 6, because the condition is so simple. The variable, however, is self-documenting.

Listing 6. Alternative simple XSLT template
<xsl:template match="Document">
  <xsl:if test="Year=2011 and Pages &gt;= 20">
    <xsl:copy-of select="Name"/>
  </xsl:if>
</xsl:template>

Tip 2: Know the difference between (x != y) and not(x = y)

The XPath expressions (x != y) and not(x = y) are different.

As a quick summary:

  • (x != y) selects nodes with both x and y, and their values are different. This expression is more exclusive than not(x = y) because the node must have x and y.
  • not(x = y) selects nodes missing either x or y or that have x and y, but their values are different. This expression is more inclusive.

With most computer languages, the expressions x != y and not(x = y) are equivalent; with XML, though, values can be undefined because a node is missing. When XML node values are compared, a question arises: How should missing values be evaluated? For a simple equality comparison, consider x = y: If either x or y is missing, the result is false. Another question is, how should the expression be negated? The following example answers this question.

Listing 7 is an XML document of documents. The data can be queried to find documents published in a given year or within a range of pages. The last document—"Prospective Projects"—does not have a year or number of pages. This document is incomplete and therefore has not been published.

Listing 7. XML source document
<Documents>
  <Document id="18396">
    <Name>Knowing the Good</Name>
    <Year>2010</Year>
    <Pages>35</Pages>
  </Document>
  <Document id="18397">
    <Name>Beyond Standards: Best Practices</Name>
    <Year>2011</Year>
    <Pages>12</Pages>
  </Document>
  <Document id="18398">
    <Name>101 Ways to Do the Same Thing</Name>
    <Year>2011</Year>
    <Pages>50</Pages>
  </Document>
  <Document id="18399">
    <Name>Prospective Projects</Name>
  </Document>
</Documents>

The XPath expression //Document[Year = 2011]/Name selects documents published in 2011. Listing 8 shows the result is the two documents.

Listing 8. Documents published in 2011
<Name>Beyond Standards: Best Practices</Name>
<Name>101 Ways to Do the Same Thing</Name>

Next, consider how to select documents that were not published in 2011. Two choices exist to negate an XPath expression: not() and !=. All documents not in the set of 2011 documents are selected with the XPath expression //Document[not(Year = 2011)]/Name. Listing 9 shows the result is the other two documents.

Listing 9. Documents not published in 2011
<Name>Knowing the Good</Name>
<Name>Prospective Projects</Name>

To select all documents that have been published but not in 2011, use the expression //Document[Year != 2011]/Name. The result is Listing 10, which shows just a single document.

Listing 10. Published documents but not in 2011
<Name>Knowing the Good</Name>

As shown, the two XPath expressions not(Year = 2011) and Year != 2011 have slightly different meanings. You use the XPath expression //Document[Pages >= 20]/Name to get all the documents with 20 or more pages. The result is Listing 11, which shows both documents matching the condition.

Listing 11. Full-length documents
<Name>Knowing the Good</Name>
<Name>101 Ways to Do the Same Thing</Name>

Next, consider the opposite: documents with less than 20 pages. The expression //Document[Pages < 20]/Name selects these documents. The sole matching document is the result in Listing 12.

Listing 12. Short documents
<Name>Beyond Standards: Best Practices</Name>

Finally, note that "Prospective Projects" does not have a known number of pages. Include such documents with not() instead of !=—for example, //Document[not(Pages >= 20)]/Name. The result is Listing 13, with two documents.

Listing 13. Documents with fewer than 20 pages or an unknown number of pages
<Name>Beyond Standards: Best Practices</Name>
<Name>Prospective Projects</Name>

To get the list of documents without a known number of pages, use the XPath expression //Document[not(Pages)]/Name. Listing 14 shows the document matching the condition.

Listing 14. Documents with unknown number of pages
<Name>Prospective Projects</Name>

The not() function is essential for handling nodes with missing attributes or elements. See Resources for a link to more tips on using XPath.


Tip 3: The value of position() depends on where it is used

The value of the position() function depends on its context—where it is used. This dependence is especially true when it's used in a predicate.

The position() function returns the one-based index of the node within the node set. The position() function counts nodes—both elements and text nodes—even if the text is just white space. The following examples illustrate position() in several different contexts.

Listing 15 is an XML document of documents and their authors. Of interest are the <Name> elements.

Listing 15. XML source document
<Documents>
  <Document id="18396">
    <Name>Knowing the Good</Name>
    <Authors>
      <Name>Bob Bloggs</Name>
      <Name>Kim Bergess</Name>
    </Authors>
  </Document>
  <Document id="18397">
    <Name>Beyond Standards: Best Practices</Name>
    <Authors>
      <Name>Bill Agnew</Name>
    </Authors>
  </Document>
  <Document id="18398">
    <Name>101 Ways to Do the Same Thing</Name>
    <Authors>
      <Name>Jay Nerks</Name>
      <Name>Paula Towne</Name>
      <Name>Carol Tinney</Name>
    </Authors>
  </Document>
</Documents>

The XSLT template in Listing 16 displays the position of each <Name> element. Listing 17 shows the results.

Listing 16. XSLT template using position()
<xsl:template match="Name">
  <xsl:value-of select="concat(position(),' ',.,'&#10;')"/>
</xsl:template>

The first column is the value of the position() function. Listing 17 shows the results of the XSLT template transform.

Listing 17. Results of Listing 16
2 Knowing the Good
2 Bob Bloggs
4 Kim Bergess
2 Beyond Standards: Best Practices
2 Bill Agnew
2 101 Ways to Do the Same Thing
2 Jay Nerks
4 Paula Towne
6 Carol Tinney

The results list the position of the <Name> element within the context of the template. Even though most name elements are the first element within their parent element, they are the second node because a blank text node (including a line break) exists between the tags. In addition, the position is relative to its parent element, not the whole document.

The templates in Listing 18 isolate the <Name> elements from the text nodes.

Listing 18. Two XSLT templates
<xsl:template match="Documents">
  <xsl:apply-templates select="//Name"/>
</xsl:template>

<xsl:template match="Name">
  <xsl:value-of select="concat(position(),' ',.,'&#10;')"/>
</xsl:template>

The result with white-space text nodes ignored is Listing 19. The value of the position() function is shown in the first column.

Listing 19. Results of Listing 18
1 Knowing the Good
2 Bob Bloggs
3 Kim Bergess
4 Beyond Standards: Best Practices
5 Bill Agnew
6 101 Ways to Do the Same Thing
7 Jay Nerks
8 Paula Towne
9 Carol Tinney

The first template selects and processes all of the <Name> elements. Because all nine of the <Name> elements are selected as a set, the position() is the index of an element within that set.

In the next example, the position() function is used in the predicate for the xsl:apply-templates statement, which selects names that have a position of 1. See Listing 20.

Listing 20. Template using position() in the predicate
<xsl:template match="Documents">
  <xsl:apply-templates select="//Name[position()=1]"/>
</xsl:template>

<xsl:template match="Name">
  <xsl:value-of select="concat(position(),' ',.,'&#10;')"/>
</xsl:template>

The result is Listing 21. Notice that only six items are returned. The first column is the value of the position() function of those Name elements that are first within their parent element.

Listing 21. Results of Listing 20
1 Knowing the Good
2 Bob Bloggs
3 Beyond Standards: Best Practices
4 Bill Agnew
5 101 Ways to Do the Same Thing
6 Jay Nerks

Note that only the first author is included. When you use position() in the predicate—that is, within the square brackets ([])—the index is relative to the <Name> element's parent. Only the first <Name> element within the <Authors> element is returned. As a shortcut, Name[position()=1] can be expressed as Name[1].

Listing 22 includes a template with the position() function placed in the template's match expression rather than in the xsl:apply-templates statement. The third template discards Name elements not in position 1.

Listing 22. Match predicate using position()
<xsl:template match="Documents">
  <xsl:apply-templates select="//Name"/>
</xsl:template>

<xsl:template match="Name[position()=1]">
  <xsl:value-of select="concat(position(),' ',.,'&#10;')"/>
</xsl:template>

<xsl:template match="Name" />

The results provided in Listing 23 are the same six elements as before, but the positions are different.

Listing 23. Results of Listing 22
1 Knowing the Good
2 Bob Bloggs
4 Beyond Standards: Best Practices
5 Bill Agnew
6 101 Ways to Do the Same Thing
7 Jay Nerks

The names in Listing 23 are the same as in Listing 21, but the position values are different. All nine names are applied to the template, but only six are matched, whereas in Listing 20, only six are applied to the template. As a shortcut, Name[position()=1] can be expressed as Name[1].

Listing 24 shows a template to process only the first <Name> element in the XML document.

Listing 24. Elements filtered before being applied
<xsl:template match="Documents">
  <xsl:apply-templates select="(//Name)[1]"/>
</xsl:template>

<xsl:template match="Name">
  <xsl:value-of select="concat(position(),' ',.,'&#10;')"/>
</xsl:template>

Listing 25 shows the single result.

Listing 25. Results of Listing 24
1 Knowing the Good

The parentheses (()) used in the select attribute are essential to correct behavior. The predicate [1] is the same as [position()=1].

Checking the position in the second template rather than in the first moves the decision from the caller of the template to the template itself, as in Listing 26.

Listing 26. Elements filtered after being applied
<xsl:template match="Documents">
  <xsl:apply-templates select="//Name"/>
</xsl:template>

<xsl:template match="Name">
  <xsl:if test="position()=1">
    <xsl:value-of select="concat(position(),' ',.,'&#10;')"/>
  </xsl:if>
</xsl:template>

The check for position has been moved to within the template itself. This check is part of an xsl:if statement rather than a predicate in the match expression. If the predicate is in the template's match expression—that is, <xsl:template match="Name[1]">—the results are those in Listing 23. The results of Listing 26 are given in Listing 27.

Listing 27. Results of Listing 26
1 Joe Bloggs

Listing 28 includes a template to ignore white space text nodes that affect the position of the <Name> elements in Listing 17.

Listing 28. Template to ignore text nodes
<xsl:template match="*">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="Name">
  <xsl:value-of select="concat(position(),' ',.,'&#10;')"/>
</xsl:template>

Listing 29 shows the results with the text nodes ignored.

Listing 29. Results of Listing 28
1 Knowing the Good
1 Bob Bloggs
2 Kim Bergess
1 Beyond Standards: Best Practices
1 Bill Agnew
1 101 Ways to Do the Same Thing
1 Jay Nerks
2 Paula Towne
3 Carol Tinney

Different results are returned by the position() function depending on where it's used and whether it's in a template's match expression, in a predicate, or in the selected node set of an xsl:apply-templates.


Tip 4: Selecting the first element with a certain name

You can select the first element in an XML document with the name Name using either //Name[not(preceding::Name)], which is required for a template match, or (//Name)[1], if used in a select attribute. The easiest method for selecting the first in a set of elements is with a predicate of value 1. For example, Listing 30 is an XML document of documents with name, year published, and number of pages.

Listing 30. XML source document
<Documents>
  <Document id="18396">
    <Name>Knowing the Good</Name>
    <Year>2010</Year>
    <Pages>35</Pages>
  </Document>
  <Document id="18397">
    <Name>Beyond Standards: Best Practices</Name>
    <Year>2011</Year>
    <Pages>12</Pages>
  </Document>
  <Document id="18398">
    <Name>101 Ways to Do the Same Thing</Name>
    <Year>2011</Year>
    <Pages>50</Pages>
  </Document>
</Documents>

The XPath expression //Document[1]—or, alternately, /Documents/Document[1]—selects the first document element. The result is Listing 31.

Listing 31. First document
<Document id="18396">
  <Name>Knowing the Good</Name>
  <Year>2010</Year>
  <Pages>35</Pages>
</Document>

The XPath expression selects the list of <Document> elements and then returns the first one. The predicate [1] means "the element that has a position of 1." Another way of expressing the same thing is //Document[position()=1].

Next, consider how to select the name of the first document. The <Name> element is a child node of the <Document> element. Select the child by appending its tag name to the XPath—that is, //Document[1]/Name, which returns the <Name> element of the first <Document> element. The result is Listing 32.

Listing 32. Name element of the first document
<Name>Knowing the Good</Name>

The XPath expression //Name[1] selects the first <Name> element regardless of where it's located in the XML document; however, there is a problem. The unexpected result is Listing 33. Three elements are returned instead of just one.

Listing 33. Unexpected results
<Name>Knowing the Good</Name>
<Name>Beyond Standards: Best Practices</Name>
<Name>101 Ways to Do the Same Thing</Name>

XPath 1.0 Axes

An XPath axis defines the direction of navigation through an XML document. The elements in a document form a tree of nodes. From a given element within the tree, there are four primary directions: up the chain of parent elements, down to the child nodes, forward to the next sibling nodes in the document, and backward to previous siblings. Axes such as those in the following list create a subset of nodes within the document:

  • ancestor. Parent, parent's parent, and so on.
  • ancestor-or-self. Context node and its ancestors.
  • attribute. Attributes of the element.
  • child. Immediate children.
  • descendant. Children, children of children, and so on.
  • descendant-or-self. Context node and its descendants.
  • following. All nodes after the context node in document order.
  • following-sibling. All following siblings.
  • namespace. Namespace nodes of the context element.
  • parent. Parent of the context node.
  • preceding. All nodes before the context node in document order.
  • preceding-sibling. All preceding siblings.
  • self. The context node itself.

Three elements are returned when only one is expected. The first <Name> element in each<Document> element is selected. If a <Document> element contained more than one <Name> element, only the first one would be returned.

How you select the first <Name> element in the XML document depends on how you use XPath. In an XSLT template match attribute, the options are more limited than with the select attribute. For a match XPath expression, use the XPath axis preceding to choose the first one. Listing 34 illustrates the expression.

Listing 34. Template match using the preceding axis
<xsl:template match="//Name[not(preceding::Name)]">

The expected result, the first element, is Listing 35.

Listing 35. Results of the template in Listing 34
<Name>Knowing the Good</Name>

The expression means "select the <Name> element that has no <Name> elements earlier in the XML document."

For a select expression, such as xsl:apply-templates statements, the XPath is more flexible. Although the expression in Listing 34 works, using carefully applied parentheses does the job more cleanly and is easily adapted to select the second, third, or any other index. See Listing 36.

Listing 36. Template match using the preceding axis
<xsl:apply-templates select="(//Name)[1]"/>

The result is Listing 37, which is the same as Listing 35.

Listing 37. Results of the template in Listing 36
<Name>Knowing the Good</Name>

The expression selects all the <Name> elements, then returns the first one.

Careful placement of parentheses and axes is important when selecting the desired results.


Tip 5: Handling XPath select expressions that fail to match documents with a default namespace

The default namespace of an XSLT does not apply to its XPath expressions. Three possible solutions exist:

  • Delete the XML document's default namespace.
  • Add a namespace prefix to XPath expressions.
  • Preprocess to remove the namespace.

Option 1: Delete the XML document's default namespace

If the XML document can be modified, delete the default namespace. Listing 38 is an XHTML document—by definition, an XML document—with a default namespace.

Listing 38. XHTML document with a default namespace
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>This is the title</title>
  </head>
  <body>
    <p>Hello world.</p>
  </body>
</html>

Option 2: Add a namespace prefix to XPath expressions

Listing 39 is an XSLT in which the XML document's default namespace is assigned a prefix. The prefix xhtml was chosen for the example, but any prefix is acceptable.

Listing 39. XSLT using a namespace prefix
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xhtml="http://www.w3.org/1999/xhtml" 
    xmlns="http://www.w3.org/1999/xhtml" 
    exclude-result-prefixes="xhtml" >
  <xsl:output method="xml" version="1.0"/>
  <xsl:template match="xhtml:title">
    <title>Replaced with a new title</title>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Listing 40 shows the resulting XHTML document. The text in the <title> element has been correctly replaced. The xhtml: prefix is excluded from the transformed output document by using the exclude-result-prefixes attribute in the XSLT.

Listing 40. Transformed XHTML document
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Replaced with a new title</title>
  </head>
  <body>
    <p>Hello world.</p>
  </body>
</html>

Option 3: Preprocess to remove the namespace

Removing the namespace from the XML document by preprocessing it with an XSLT might be an option, but doing so might be time-consuming. The XSLT in Listing 41 copies text, element, and attribute nodes in the source XML document, but namespace nodes and the DOCTYPE declaration are omitted.

Listing 41. XSLT to remove namespace nodes
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0"/>

  <!-- copy elements without namespace -->
  <xsl:template match="*">
    <xsl:element name="{name()}">
      <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="@*|text()|processing-instruction()|comment()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

This two-pass approach transforms the document twice, with the result of the first XSLT transformed by a second XSLT. For more on multi-pass transforms, see Resources.

Option 1, if you can apply it, is the easiest and simplest solution. Option 2 is possible if the XML documents consistently have a default namespace, which is usually the case. Although a little extra typing is required to add the namespace prefixes to the XPath expressions, this solution works and doesn't add extra processing. Option 3 processes the XML document twice and is, therefore, slower. Concerns about whether the source XML document has a default namespace, however, are eliminated.


Conclusion

Binary logic in XPath expressions is a bit more complex than simply true and false. The absence of a value resolves to False when comparing for equality or inequality. Conversion of Boolean values to strings, when interpreted as a Boolean, is evaluated as True. The third tip explained the relative nature of the position() function depending on its context, and the fourth tip showed how to use the XPath preceding axis or a predicate to select the first element of a given name in a list. Finally, the common problem of failing XPath select expressions was identified as the result of a default namespace in the XML document, and several possible solutions were given.

XPath is a powerful functional language for selecting nodes in an XML document. But as with all computer languages, XPath comes with a learning curve. Experiment with these examples to gain an even deeper understanding.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=659549
ArticleTitle=Stay on the XPath
publish-date=05242011