Cauthon
Cauthon

Reputation: 520

Unclear use of // in XPath

Let's look at the following XML file:

<a>
  <b w="w">
    <b1 x="x" />
    <b2 y="y" />
  </b>
</a>

The following XPath query returns elements b1 and b2:

/*/*//*

From this I conclude that //* means to select all elements that are descendants of b not including b itself.

However the following XPath query returns attributes w, x, y:

/*/*//@*

So from this I conclude that //@* means to select all attributes that appear in descendants of b including b itself.

How does this work? Does // work differently for elements vs attributes, or is there something I'm missing?

Upvotes: 4

Views: 72

Answers (2)

Jon Hanna
Jon Hanna

Reputation: 113242

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

/* meanwhile identifies all child nodes from the current position.

Starting from the root, /*/*// therefore moves us to <a> (child of root) and then to <b> (all children of that <a> being that single <b>) and then selects descendant-or-self::node(), which is to say, <b>, <b1> and <b2>.

It's from that starting point of <b>, <b1> and <b2> matched by /*/*// that your two paths differ.

/*/*//* matches all child nodes of those nodes. Since <b1> and <b2> don't have child nodes, this matches only the child nodes of <b>: <b1> and <b2>.

/*/*//@* matches all attributes of those nodes. Since <b>, <b1> and <b2> all have attributes, all of those attributes are matched.

From this I conclude that //* means to select all elements that are descendants of b not including b itself.

Yes, but only indirectly. It means "select all elements that are descendants of b including b itself, and then find their children". This amounts to "all descendants of b but not b" but it went through "including b" to get there.

Upvotes: 2

collapsar
collapsar

Reputation: 17238

The apparent contradiction stems from the interpretations of the shorthand notation for xpath expressions.

// in xpath expressions is a shorthand for the xpath axis //descendant-or-self::node()/. Specifying an element in an xpath, eg. by its tag name actually queries the element on the child axis.

The child axis does not apply when querying attributes - @ represents its own axis, namely attributes.

Therefore the matching appears to include one more level in the tre representation.

Upvotes: 2

Related Questions