There is an anchor tag, whose value can be changed by the user. Now, i want to write an Xpath query that searches for multiple link text names in one statement itself.
Signin
now, link text value can be changed by user profile. for eg, "Login", "Log-in", "Click here to login" or "Login now"
If i write xpath:-
//a[contains(text(),'Login') or contains(text(),'Log-in') or contains(text(),'Login now') or contains(text(),'click here to Login')]
Then it fails. I need to click this element using Selenium.
Please help.
Important notes:
Only use contains() when you need substring testing. See What does contains() do in XPath?
Understand string-values: See Testing text() nodes vs string values in XPath
Beware of whitespace variations. See What is the purpose of normalize-space()?
Your posted markup has Signin, but your XPath does not.
Mind case sensitivity: click here to Login is not the same as Click here to Login.
XPath 1.0
If you're certain there are no whitespace variations:
//a[.='Login' or .='Log-in' or .='Click here to login' or .='Login now']
Otherwise:
//a[ normalize-space()='Login"
or normalize-space()='Log-in'
or normalize-space()='Click here to login'
or normalize-space()='Login now']
XPath 2.0
//a[normalize-space()=('Login','Log-in','Click here to login','Login now')]
XPath is based on sequences. So you can use a comma separated list, i.e. sequence, to imitate logical OR conditions.
XPath
//a[text()=("Login","Log-in","Click here to login")]
Related
<a href="/company/10676229"
onclick="javascript:_paq.push(['trackEvent', 'SearchSuggestions']);"
title="View company">
<strong>RECRUIT</strong>
" ZONE "
<strong>RECRUITMENT</strong>
" LIMITED "
</a>
I'm trying to extract the text from the above a node in the form "RECRUIT ZONE RECRUITMENT LIMITED" - all on one line - but so far can only get them on separate lines. Since I'm running over a few hundred of these records, all with different patterns of bold and regular text it would be good if i can use an XPath expression to extract all the text on one line straight out, rather than having to use loads of logic afterwards to try and concatenate them together. Stuck with XPath 1.0.
I feel like there would be an expression to do this but struggled with research so far and not sure what else to try.
So far I've tried:
//a[#title="View company"]//text()[normalize-space()]
which returns a list but the text has been separated so all bold text is appearing on different lines to the rest for each a node
XPath 1.0
As already answered by #Andersson (+1), this XPath,
normalize-space(//a[#title="View company"])
will return
RECRUIT " ZONE " RECRUITMENT " LIMITED "
for the markup shown in your question.
In the comments, you've said that your actual markup will include multiple such a elements and that you'd like to select and similarly obtain the text for each. This is not possible with XPath 1.0 alone; you'll have to iterate over selected nodes and process them in the hosting language. In XPath 1.0, only the first of all such a elements will be processed by normalize-space().
XPath 2.0
XPath 2.0 can handle the task with this XPath,
//a[#title="View company"]/normalize-space()
which will apply normalize-space(), which first takes the string value and then trims leading and trailing space and consolidates interior space, for each node selected in the previous step.
Try below to get text content of link as single string:
normalize-space(//a[#title="View company"])
I have a page in firefox (no frame) which contains the following part of html code:
...
<div class="col-sm-6 align-right">
<a href="/efelg/download_zip" class="alert-link">
Download all results in .zip format
</a>
</div>
...
which I want to select with a selenium XPATH expression. In order to test my XPATH expression, I installed an add-on for firefox called 'TryXpath' in order to check my expression. However, the expression seems to be incorrect, as no element is selected. Here is the expression:
//a[text()= "Download all results in .zip format"]
but what is wrong with that expression? I found it in different SO answers - but for me this does not seem to work. Why do I get 0 hits? Why is the expression wrong find the html element I posted above (no frame, element is visible and clickable...)
You can try this:
//a[contains(text(),'Download all results in .zip format')]
it is working in my side, Please try at let me know
The reason your XPath isn't selecting the shown a element is due to the leading and trail white space surrounding your targeted text. While you could use contains() as the currently upvoted and selected answer does, be aware that it could also match when the targeted string is a substring of what's found in the HTML in an a element -- this may or may not be desirable.
Consider instead using normalized-space() and testing via equality:
//a[normalize-space()='Download all results in .zip format']
This will check that the (space-normalized) string value of a equals the given text.
See also
Testing text() nodes vs string values in XPath
I'm fairly new to XPath and wanted to see how granular you can get when accessing various HTML components.
I'm currently using the this xpath
//*[#id=\"resultsDiv\"]/p[1]/a
to access the HTML (abbreviated) below:
<p style="margin:0;border-width:0px;">Bill%20Jones</p>
The XPath returns this: Bill%20Jones
But what I'm trying to get is simply the PersonID = 140476.
Question: Is it possible to write an XPath that results in 140476, or do I need to take what was returned and use a regular expression other method to access the PersonID.
If this XPath,
//*[#id=\"resultsDiv\"]/p[1]/a
selects this a element,
Bill%20Jones
then this XPath,
substring-after(//*[#id='resultsDiv']/p[1]/a/#href, 'PersonID=')
will return 140476 alone, as requested.
<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?
Other answers have missed the actual problem here:
Yes, you could match on #title instead, but that's not why OP's
XPath is failing where it may have worked previously.
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()
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.
You can try this XPath..Its just select element by attribute
//a[#title,'home']
I have a readymade code and i'm trying to write tests for it using selenium. This is how my code looks like in element tab of chrome:
<table id="xyz">
<tbody>
<tr>...</tr>
"
I am not able to retrieve this text.
"
</tbody>
</table>
Doing this $x("//*[contains(text(),'I am not able to retrieve this text')]"); in console tab of chrome shows no results. I'm able to get text by this command if the text is defined in a div, span etc. (Also case sensitivity is not a problem).
In code that text is appended in tbody using jQuery('tbody').append( abc() ); and abc() function returns this text in this way pqr.html();
Now my questions is what xpath expression should i write to grab this text? And i am looking for a pure xpath expression i.e no java functions etc.
contains() expects singular value as the first parameter. An HTML element may have more than one text nodes children in it, in which case, your attempted XPath will evaluates only the first text node. According to the sample HTML posted, the first text node of <tbody> which will be evaluated consists of newline and some spaces, hence your XPath didn't consider <tbody> a match and returned no result.
To avoid the problem explained above, use contains() in predicate for individual text nodes like the following :
//*[text()[contains(.,'I am not able to retrieve this text')]]
or this way if you want to return the text node itself instead of the parent element :
//*/text()[contains(.,'I am not able to retrieve this text')]
That table element is probably within a frame. To access contents within a frame you need to first switch to it. You can use the "switch to" method in selenium. Refer this answer and this one.
For the same reason it is not working in the Chrome Dev Tools console. In the console tab, there is dropdown containing a list of frames. Make sure you select the correct frame in which the specific element exist and then execute your XPath.