2

Given the following html:

<span class="fum foe"> <b>45</b> results </span>

...can anyone tell me why the following xpath is not finding it?

//span[contains(text(), "results")]

I've attempted some "normalize-space" mojo, but haven't been able to get anything to work. Went with a "fum foe" workaround but trying to understand what I'm not understanding.

Many thanks in advance!

2 Answers2

1

This doesn't match because of the 'b' tag.

This one works:

//span[contains(., "results")]

. is a multiple node text search.

Learn about the dot.

And the explanation by one of XPath dad, thanks Mr Kay

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • Thanks very much! I had a feeling it was something along those lines. I'm still trying to understand the logic behind this, so any pointers you have towards tutorials / manual entries which might help with that would be very much appreciated. For now, I'll investigate recursive text searches & hopefully that will help put me on the path to clarity. – Jason Witherspoon Jul 01 '20 at 21:34
  • Added link to explain the `.` – Gilles Quénot Jul 01 '20 at 22:44
1

In XPath 1.0, when a function like contains() expects a string as its first argument, and you supply a node-set containing multiple nodes (text() in your example), the node-set is converted to a string by ignoring all nodes except the first.

This elephant trap was removed in XPath 2.0, which makes this situation an error. In both versions, you can test whether any of the text nodes contains "results" using

//span[text()[contains(., "results")]]

But you would probably be quite happy to select the element if the word "contains" is split across multiple text nodes, in which case the correct query (again, in both versions) is

//span[contains(., "results")]

Use of text() in XPath expressions is very often a code smell.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164