132

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
  • 34,866
  • 14
  • 107
  • 142
developer
  • 7,252
  • 14
  • 49
  • 57
  • 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

3 Answers3

225

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
  • 240,661
  • 26
  • 293
  • 431
  • 4
    @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
19

Try

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

Gregoire
  • 24,219
  • 6
  • 46
  • 73
2

Better use //*[normalize-space(text()) = 'qwerty'] . If there are any whitespaces around the text, they will be removed.