What's the difference between //node and /descendant::node in xpath?

53,689

Solution 1

see http://www.w3.org/TR/xpath#path-abbrev

// is just an abbreviation for the descendant:: axis

Edit

To quote:

//para is short for /descendant-or-self::node()/child::para

That is, it refers to all para which are a child of the context node or any node descended from the context node. As far as I can tell that translates into any descendant para of the context node.

Solution 2

There's a difference in the context group. //para[1] is short for /descendant-or-self::node()/child::para[1], which returns every para that is the first child of its parent. /descendant::para[1] returns only the first para in the entire subtree.

Solution 3

In your case

 id('books')//td[@class='title']

and:

 id('books')/descendant::td[@class='title']

return the same result.

But in fact, like it was already stated before, id('books')//td[@class='title'] means id('books')/descendant-or-self::node()/td[@class='title'] which is different from id('books')/descendant::td[@class='title'] in concept.

See the following note:

NOTE: The location path //para[1] does not mean the same as the location path /descendant::para[1]. The latter selects the first descendant para element; the former selects all descendant para elements that are the first para children of their parents.

this note was taken from http://www.w3.org/TR/xpath#path-abbrev

Solution 4

Other than terseness, I'm not aware of any difference.

Solution 5

I realize this answer is more of a functional correctness, but in case it helps anyone, I stumbled across a key difference today.

When selecting elements based on some property of a descendant (like attribute). For example:

...
<foo id="ID1">
    <bar>
        <baz at2="c" />
    </bar>
</foo>
<foo2 id="ID2">
    <bar>
        <baz at2="d" />
    </bar>
</foo2>
...

To select the id attribute of all elements who have a descendant with an attribute at2=c:

This xpath will select foo and foo2:

//*[//*[@at2="c"]]/@id

while this xpath will only select foo:

//*[descendant::*[@at2="c"]]/@id
Share:
53,689
Dave Hunt
Author by

Dave Hunt

I'm an automation engineer developing tools and test solutions for Mozilla and an active contributor to the Selenium open source project.

Updated on March 08, 2021

Comments

  • Dave Hunt
    Dave Hunt over 3 years

    I use a lot of XPath when locating elements in web pages using Selenium, and have moved away from using node1//node2 towards using node1/descendant::node2 more recently. What's the difference between the two methods? Is one more efficient than the other?

    Example XML snippet to demonstrate:

    <div id="books">
      <table>
        <tr><td class="title">Lord of the Rings</td><td class="author">JRR Tolkein</td></tr>
        <tr><td class="title">The Hitch-Hikers Guide to the Galaxy</td><td class="author">Douglas Adams</td></tr>
      </table>
    </div>
    

    So it'd be:

    id('books')//td[@class='title']

    or:

    id('books')/descendant::td[@class='title']