2

XPath - What is the difference between (//first//*)[1] and //first//*[1] ? How it works?

A sample XML file is:

<root> 
    <first>
             <second>
              Test
             </second>

             <second>
              <third>Test2</third>
         </second>

    </first>
</root>

(//first//*)[1] gives:

<second>
 Test
</second>

but //first//*[1] gives:

  <second>
    Test
  </second>
<third>Test2</third>  
lexicore
  • 42,748
  • 17
  • 132
  • 221
Vivyen
  • 67
  • 1
  • 6

3 Answers3

4

In both cases, //first select all first elements, and //first//* selects all elements descendents of first. Then, the difference is:

  1. (//first//*)[1] selects from all of those elements, only the first.
  2. //first//*[1] selects from all of those elements, every first child.

As you've seen for your XML, second is selected by XPath #1 because it is the first of all the descendents of first. (Your element name choices are a bit non-ideal.) Both second and third are selected by XPath #2 because they're both first among their respective siblings.

kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • Thanks a lot !, so parentheses makes xpath parse it like a whole , but //first//*[1] will parse relatively to each node? – Vivyen Nov 23 '16 at 01:33
  • Right, the predicate `[1]` binds more tightly than `/`, so without the parens, **first child** is the default rather than just **first**. – kjhughes Nov 23 '16 at 03:15
3

// means /descendant-or-self::node()/. So //first//*[1] means /descendant-or-self::node()/child::first/descendant-or-self::node()/child::*[1].

Predicates bind more tightly than "/", so this means

/descendant-or-self::node()/ child::first/ descendant-or-self::node()/ (child::*[1])

Informally: find all the elements called "first"; then for each of these, find every descendant element that is the first element child of its parent.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
1
(//first//*)[1] - returns first element found no matter where  

For example if you find multiple elements in different parts of the page it will return the first found.

//first//*[1] - returns first element form each section  

For example if you found multiple elements in different sections of the page it will return the first one from each section. In your example first element <second> from <first> and first element from <second>.

If you switch the 2 seconds between them it should return the same.

Usually you would use //first//*[1] to get the first element from a list (elements on the same level).

lauda
  • 4,153
  • 2
  • 14
  • 28