123

In Xpath, I am wanting to select elements that equal a specific value.

Sample XML data:

<aaa id="11" >
    <aaa id="21" >
        <aaa id="31" ></aaa>
        <bbb id="32" >
            <aaa id="41" ></aaa>
            <bbb id="42" ></bbb>
            <ccc id="43" ></ccc>
            <ddd id="44" >qwerty</ddd>
            <ddd id="45" ></ddd>
            <ddd id="46" ></ddd>
        </bbb>
    </aaa>
    <bbb id="22" >
         <aaa id="33" >qwerty</aaa>
         <bbb id="34" ></bbb>
         <ccc id="35" ></ccc>
         <ddd id="36" ></ddd>
         <ddd id="37" ></ddd>
         <ddd id="38" ></ddd>
    </bbb>
    <ccc id="23" >qwerty</ccc>
    <ccc id="24" ></ccc>
 </aaa>

Now, using the XPath:

//ccc[.='qwerty']

I get the correct, expected results:

Name    Value
ccc     qwerty

Now, using the XPath:

//aaa[.='qwerty']

I get unexpected results:

Name    Value
aaa      
aaa     qwerty

And what I am particularly interested, is how to select any element with that value

XPath:

//*[.='qwerty']

I get very strange unexpected results:

Name    Value
aaa
bbb
ddd     qwerty
bbb     qwerty
aaa     qwerty
ccc     qwerty

Can someone explain these results, and how to fix my XPath expressions to get more expected results?

Nakilon
  • 33,683
  • 14
  • 104
  • 137
developer
  • 6,834
  • 14
  • 48
  • 56
  • 1
    Because XPath `. =` is different than XPath `text() =`. See [**matching text nodes is different than matching string values**](http://stackoverflow.com/a/34595441/290085) to learn why. – kjhughes Mar 12 '17 at 22:37

2 Answers2

208

The XPath spec. defines the string value of an element as the concatenation (in document order) of all of its text-node descendents.

This explains the "strange results".

"Better" results can be obtained using the expressions below:

//*[text() = 'qwerty']

The above selects every element in the document that has at least one text-node child with value 'qwerty'.

//*[text() = 'qwerty' and not(text()[2])]

The above selects every element in the document that has only one text-node child and its value is: 'qwerty'.

Dimitre Novatchev
  • 235,605
  • 26
  • 291
  • 421
  • 3
    @iHeartGreek: Glad it works. How about accepting / upvoting ? `text()` is one of the possible *node-tests* in XPath, meaning "is this a text node?". Other nodetests are `comment()`, `processing-instruction()`, or just `node()`. – Dimitre Novatchev Jul 08 '10 at 20:55
18

Try

//*[text()='qwerty'] because . is your current element

Gregoire
  • 23,201
  • 6
  • 43
  • 71