find element by xpath with contains(node()) AND contains(#attribute) - selenium

I'm trying to locate an element by checking innerHTML (property node()) and some attribute (e.g. #class).
Both methods works separately but I can't combine them with "and"
HTML part:
<tr class="tableRow1">
<td nowrap="" class="ct">
<input type="CheckBox" name="RowKey" tabindex="17" value="15635">
<img src="/tm/images/1pixel.gif" style="height:9px;width:9px;border:0" name="RowIndicator">
</td>
<td class="lt" title="ID">XXXXX</td><nobr>0021234567</nobr><td class="rt">1.00</td>
</tr>
So I need to locate this node of class="tableRow1" (from many others) by catching this part:
<nobr>002123456</nobr>.
This two works (but catching several elements):
.find_element_by_xpath('//tr[contains(node(), "0021234567")]')
.find_element_by_xpath('//tr[contains(#class, "Row")]')
This one doesn't:
.find_element_by_xpath('//tr[contains(node(),"0021234567") and contains(#class,"Row")]')

Try this XPath-1.0 expression:
descendant::*[contains(node(), "0021234567")]/ancestor::tr[contains(#class, "Row")][1]
or in a complete instruction
.find_element_by_xpath('descendant::*[contains(node(), "0021234567")]/ancestor::tr[contains(#class, "Row")][1]')
This instruction selects the first tr ancestor - which has a class attribute which contains the value Row - of a (global) node() which contains the value 0021234567.

Your two XPath selectors are selecting different nodes.
The node that contains the string is a descendant of the <tr> node with the class name. That is why when you are putting both conditions for one node it doesn't find any matching node.
Try this:
.find_element_by_xpath('//[contains(node(), "0021234567")]/ancestor::tr[contains(#class), "Row"]')

To locate the <tr> nodes which contains the child <nobr> nodes you can use the following solution:
driver.find_element_by_xpath("//nobr//ancestor::tr[contains(#class, 'Row')]")
Note: It is assumed that the innerText within the <nobr> is a variable else the innerText can be included within the XPath expression as well.

So I need to locate this node of class="tableRow1" (from many
others) by catching this part:
<nobr>002123456</nobr>
The XPath expression should be:
//tr[#class='tableRow1'][.//nobr='002123456']
That is the basic. Then you could adjust that to your situation.
Example 1 (many posible classes tokens):
//tr[contains(concat(' ',#class,' '),' tableRow1 ')][.//nobr='002123456']
Example 2 (posible white space in nobr):
//tr[contains(concat(' ',#class,' '),' tableRow1 ')]
[.//nobr[normalize-space()='002123456']]
Example 3 (class token starts with 'tableRow'):
//tr[contains(concat(' ',#class,' '),' tableRow')]
[.//nobr[normalize-space()='002123456']]

Related

Why doesn't my XPath expression return any results?

I have the following html:
<html>
<body>
<table>
<tr>
<tr>
<tr>
<tr>
<tr>
<td>Color Digest </td>
<td>AgArAQICGQMVBBwTIRQHIwg0GUMURAZTBWQJcwV0AoEDAQ </td>
</tr>
<tr>
<td>Color Digest </td>
<td>2,43,2,25,21,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, </td>
</tr>
</table>
</body>
</html>
and the following xpath:
tr[td='Color Digest']/td
and I'm getting zero results.
Can someone explain why?
Inside xPath expression we can use attribute name and tag name(when it has text) as well. Here both <tr> and <td> are tag names. The valid xPath expressions be like,
//tagname[#attributeName='value']
and
//tagname[#tagname='text']
Inside td there is only text available so you need to write xPath like
//td[text()='Color Digest ']
or
//tr[td='Color Digest ']
If you need to use specific element then please use the match number like below,
(//td[text()='Color Digest '])[1]
or
(//tr[td='Color Digest '])[1]
Why it showed 0 matches for your xPath?
You haven't given space at end of Digest.
Yours:
//tr[td='Color Digest']/td
Corrected one:
//tr[td='Color Digest ']/td
There are a few issues with your XPath
tr[td='Color Digest']/td
^ 1
^ 2
^ 3
XPaths should start with a / (child) or // (descendant). Child basically means one level down where descendant means one or more levels down.
tr should be //tr in this case since there are no root TRs.
You've used td when it looks like you meant to use . or text() which indicates two variations of text within the element. . means squash the contained text of all descendant nodes and text() means the contained text of just the current node.
Either text() or . will work in this case but I would generally use text() just to be safe.
[td='Color Digest'] should be [text()='Color Digest']
If you look at the HTML you provided, the text in the first TD actually contains a space at the end, e.g. 'Color Digest ' vs 'Color Digest'. That space is required unless you use a function like contains().
[td='Color Digest'] should be [text()='Color Digest ']
For this last one, I'm not sure what you are actually looking for, /td.
For the TD that contains the "Color Digest " text, it has no child. If you meant sibling TD, that would require /following-sibling.
/td should be /following-sibling::td[1].
Putting all of this together,
//tr[text()='Color Digest ']/following-sibling::td[1]
and it would return the following elements
<td>AgArAQICGQMVBBwTIRQHIwg0GUMURAZTBWQJcwV0AoEDAQ </td>
<td>2,43,2,25,21,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...</td>

Selenium xpath with multiple conditions and fetch element value

I have a condition where tr row which generates dynamic value:
<tbody>
<tr id="24686" tabindex="0">
<td class="nowrap xh-highlight" style="padding: 3px 8px;">Available</td>
</tr>
</tbody>
I have Xpath 1: (//tbody/tr/td[contains(text(),'Available')])[1] which returns
Available
and Xpath 2: //tr[1]/#id which returns
ld_9050427
22707
The condition is that I want to generate one xpath which will return first number whose status is Available and then return its ID. Later on I want to use this same id to carry on later process?
I tried something like below but it didn't work
(//tbody/tr[/#id and/td[contains(text(),'Disponible')]])[1]
If you want to select tr that has id attribute (any) and table cell with text "Available" try
//tr[#id and td='Available']
to extract id value for further use you need get_attribute/getAttribute method
To find the first number whose status is Available and then return its ID you can use the following solution:
xpath:
"//tbody//tr//td[text()='Available']/.."
Note 1: The .. in the xpath refers to the ancestor node
Note 2: As you are looking for the first match with the implemented condition, you have use either:
Python:
find_element_by_xpath()
Java:
findElement()
C#:
FindElement()
Note 3: Finally you have to use getAttribute("id") / get_attribute("id") to extract the value of the id attribute as follows:

How to find an item in Selenium WebDriver?

I want to find the following item using Selenium. The value of the class changes whenever there is a change. This is inside a complex page (multiple iframes, and other items loaded dynamically). The only unique id is itemid, which is dynamic value and title combination. If I click on this Action, am getting another new set of complex items. I am new to Selenium. How to do that?
HTML:
<td itemid="xxyyy.as123" title="Actions" nowrap="" class="text-button">Actions <img src="../row.gif"></td>
<td itemid="xxyyy.as123" title="Actions" nowrap="" class="text-button button-active">Actions <img src="../row.gif"></td>
<td itemid="xxyyy.as123" title="Actions" nowrap="" class="text-button button-hover">Actions <img src="../row.gif"></td>
The code I tried:
Find by Xpath
var element=driver.FindElement(By.XPath("html/body/div[id='pageContent']/iframe/#document/ht‌ml/frameset/frame[name='detailsDisplay']/#document/html/body/form[name='tableForm‌']/div[id='divToolbarContainer']/div[id='divToolbar']/div[1][class='toolbar']/tab‌​le/tbody/tr/td[title='Actions']"));
Find by Link Text
var element = driver.FindElement(By.LinkText("Actions"));
Any help would be appreciated.
Try
By.CssSelector("td[title="Actions"]");
By.CssSelector("td[itemid="xxyyy.as123"]");
By.CssSelector("td[itemid="xxyyy.as123"][title="Actions"]")
Create Dynamic CSS Selector.
For Example:
driver.FindElement(By.CssSelector("td[itemid$="xxyyy."]")).Click();
Note: In dynamic Elements, there is always a part of locator wich is fixed. we need to generate the locator using this part.
If fixed part is at starting - Use Carrot Character (^)
If fixed part is at Middle - Use Asterisk sign (*)
If fixed part is at End - Use Doller sign ($)
Finally I was able to achieve it, by using the frame names.
driver.SwitchTo().Frame("content").SwitchTo().Frame("detailsDisplay");
var element = driver.FindElement(By.XPath("//*[#id=\"divToolbar\"]/div[1]/table/tbody/tr/td[1]"));
Thanks everyone.

Python Selenium auto-test (How to get text of a column)

Using Xpath tool from chrome dev tools, I have been able to get xpath string and a td object. I 'm just wondering how do we find the value of text in a td object using selenium python web-drivers?
for your case you can use .gettext() method of selenium.
Once I found that, the attribute within td which contains the text is changing and i was supposed to fetch the text in those attribute.
like
<td class="table__cell" data-col-index="1">
<div class="ec-table__cell-content ">813.75</div>
</td>
<td class="table__cell" data-col-index="2">
<span class="ec-table__cell-content ">522.12</span>
</td>
So to get text within all td in a list, I used dynamic Xpath way:
By.xpath("//td[contains(#class,'table__cell')]/following::*").getText()
Try to search by xpath. Relatively to some ID.
Example of:
id("body_content")/table/tbody/tr/td[3]
in this case will be shown exact elements of 3rd column only.

Selenium RC link locator cannot find link inside table

I has a page as follow:
<table>
<tr>
<th>Company Name</th>
</tr>
<tr>
<td> What Ever Company</td>
</tr>
</table>
The company name is placed arbitrary in the table, so I can only use the link's text to locate the link:
selenium.click("link='What Ever Company'");
However, it says: ERROR:Element link='What Ever Company' not found.
What is the problem here? Is there any other way to click on the link?
Many thanks.
EDIT
Seem that the problem is I have several links with the same text (my bad). After making the link's text unique, I use selenium.click("//a[contains(text(),'Test Campaign 1756237989')]") and it works.
Could this be because you're forgetting the space at the start of the link?
selenium.click("link=' What Ever Company'");
^
Another possible way of clicking the link, is to use an XPath expression:
selenium.click("//a[contains(.,'What Ever Company')]");
This will match all links with 'What Ever Company' in it.
If you want it more exact:
selenium.click("//a[.=' What Ever Company']");
This will only match if the anchor equals ' What Ever Company'.
Another option is to make the search more specific (i.e. tell the locator this link is always inside a <td> with an <a> inside):
selenium.click("//td[a]/a[contains(.,'What Ever Company')]");
The //td[a] looks for all <td> elements with <a> inside. (Differs from //td/a in that if you look for elements with //td[a][2] you get the second <a> which is inside a <td>, while //td/a[2] on the other hand gets the second <a> of the first <td>.)
EDIT: I thought using . as a reference to text() in the XPath expressions should work, but if it doesn't, try using text() instead.
Try these XPaths:
"//table/tr[2]/td/a"
or
"//a[contains(text(), 'What Ever Company')]"
Should work.