Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't my XPath select link/button based on its label text?

<a href="javascript:void(0)" title="home">
    <span class="menu_icon">Maybe more text here</span>
    Home
</a>

So for above code when I write //a as XPath, it gets highlighted, but when I write //a[contains(text(), 'Home')], it is not getting highlighted. I think this is simple and should have worked.

Where's my mistake?

like image 358
Shoaib Akhtar Avatar asked Sep 29 '17 10:09

Shoaib Akhtar


2 Answers

Other answers have missed the actual problem here:

  1. Yes, you could match on @title instead, but that's not why OP's XPath is failing where it may have worked previously.
  2. Yes, XML and XPath are case sensitive, so Home is not the same as home, but there is a Home text node as a child of a, so OP is right to use Home if he doesn't trust @title to be present.

Real Problem

OP's XPath,

//a[contains(text(), 'Home')]

says to select all a elements whose first text node contains the substring Home. Yet, the first text node contains nothing but whitespace.

Explanation: text() selects all child text nodes of the context node, a. When contains() is given multiple nodes as its first argument, it takes the string value of the first node, but Home appears in the second text node, not the first.

Instead, OP should use this XPath,

//a[text()[contains(., 'Home')]]

which says to select all a elements with any text child whose string value contains the substring Home.

If there weren't surrounding whitespace, this XPath could be used to test for equality rather than substring containment:

//a[text()[.='Home']]

Or, with surrounding whitespace, this XPath could be used to trim it away:

//a[text()[normalize-space()= 'Home']]

See also:

  • Testing text() nodes vs string values in XPath
  • Why is XPath unclean constructed? Why is text() not needed in predicate?
  • XPath: difference between dot and text()
like image 87
kjhughes Avatar answered Oct 08 '22 07:10

kjhughes


yes you are doing 2 mistakes, you're writing Home with an uppercase H when you want to match home with a lowercase h. also you're trying to check the text content, when you want to check check the "title" attribute. correct those 2, and you get:

//a[contains(@title, 'home')]

however, if you want to match the exact string home, instead of any a that has home anywhere in the title attribute, use @zsbappa's code.

like image 25
hanshenrik Avatar answered Oct 08 '22 09:10

hanshenrik