Why doesn't my XPath expression return any results? - selenium

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>

Related

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

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']]

Unable to find correct Target selector to click an element

Please see the image below which shows code of the web page in Developer Tools window and advise me the correct selector for 'Depreciation Models'. Text highlighted in red is constant, however the surrounding text is dynamic. So I tried using contains selector to locate but unsuccessful. I want to avoid XPATH as number of before and after div elements may keep changing.
I am using Selenium IDE hence the C#/Java code for RC/Webdriver won't help much.
Selenium IDE generated target path is this:
css=#dhxId_rgWATog7lC3E_27572|6059|6152 > td.sub_item_text > div.sub_item_text
I tried
css=contains('27572') > td.sub_item_text > div.sub_item_text
but it didn't work.
Kindly suggest. I am stuck. Thanks.
As you tried the Locator Strategy as :
css=contains('27572') > td.sub_item_text > div.sub_item_text
Reasons for not working
From the snapshot of the HTML you have provided, 27572 is not the innerText but partial string of the id attribute.
As per selenium.common.exceptions.InvalidSelectorException with “span:contains('string')”:
The :contains pseudo-class isn't in the CSS Spec and is not supported by either Firefox or Chrome (even outside WebDriver).
Solution
You can use the following xpath as per the existing DOM Tree:
xpath=//tr[#class='sub_item'][contains(#id,'27572')]//td[#class='sub_item_text']/div[#class='sub_item_text'][contains(.,'Depreciations Models')]
I guess this would be the right approach:
<style>
[id*="27572"] > td.sub_item_text > div.sub_item_text{
color:red;
}
<table>
<tbody>
<tr id="dhxId_rgWATog7lC3E_27572|6059|6152" class="sub_item">
<td class="sub_item_icon">
<i class="fa fa-user epc-down-circled-2"></i>
</td>
<td class="sub_item_text">
<div class="sub_item_text"> Depriciations Models</div>
</td>
</tr>
</tbody>
</table>
It will set all elements that have an id attribute value containing "27572" and inside of it.

How to select the drop-down items which is out of tag using xpath

I've tried several xpath's for choosing the dropdown list. But nothing is worked.
Some of the xpath's I used are as follows:
By.xpath("//table/tbody/tr[2]/td[2]/span").click;
Or
By.xpath("/td[2]/span[contains(text(),'NATIONAL IDENTITY DOCUMENT')]").click;
Please find the below html tags, I need to select the value either 'ASYLUM SEEKER PERMIT DOCUMENT' or 'NATIONAL IDENTITY DOCUMENT'.
<tbody>
<tr id="jP2Qrg" class="z-comboitem">
<td class="z-comboitem-img"/>
<td class="z-comboitem-text">
<span class="z-comboitem-spacer"/>
ASYLUM SEEKER PERMIT DOCUMENT
</td>
</tr>
<tr id="jP2Qsg" class="z-comboitem z-comboitem-over">
<td class="z-comboitem-img"/>
<td class="z-comboitem-text">
<span class="z-comboitem-spacer"/>
NATIONAL IDENTITY DOCUMENT
</td>
</tr>
</tbody>
When I try to take xpath using firepath, it is dynamic. Every time the xpath and the id is keep changing. So please suggest the xpath which works.
The text is not inside the span text and it is in second td tag. you can try with small change in your code as given below.
By.xpath("//table/tbody/tr[2]/td[2]").click;
or
By.xpath("//td[contains(text(),'NATIONAL IDENTITY DOCUMENT')]").click;
Can you check this..,
By.xpath("//*[contains(text(),'NATIONAL IDENTITY DOCUMENT')]").click;
By.xpath("//*[contains(text(),'ASYLUM SEEKER PERMIT DOCUMENT')]").click;
Try to use below XPath to match required option:
By.xpath("//td[normalize-space()='ASYLUM SEEKER PERMIT DOCUMENT']").click;
or
By.xpath("//td[.='ASYLUM SEEKER PERMIT DOCUMENT']").click;
As #Murthi said, text node is not a child of span, but td. Note that there are some specifics in locating text nodes
Here is the Answer to your Question:
To click on ASYLUM SEEKER PERMIT DOCUMENT you can use the following xpath:
By.xpath("//td[contains(.,'ASYLUM SEEKER PERMIT DOCUMENT') and not (#class='z-comboitem-spacer')]").click;
Let me know if this Answers your Question.
How about this xpaths,
Updated code
(//td[2])[1]//*[starts-with(#class,"z-com")]; // Selects ASYLUM..
(//td[2])[2]//*[starts-with(#class,"z-com")]; // Selects NATIONAL..
This should work if it doesn't have same class name in the same position.
Old xpath's
driver.findelement(By.xpath("(//td[2])[1]")); // selects ASYLUM SEEKER PERMIT DOCUMENT
driver.findelement(By.xpath("(//td[2])[2]")); // selects NATIONAL IDENTITY DOCUMENT
Find out the solution for selecting the dropdown options.
By using List method, I took the list of options available in that field and selected by using clicking the index value of list.
List<WebElement> Idtype = driver.findElements(By.xpath("//tr[2]/td[2][#class = 'z-comboitem-text']"));
Idtype.get(0).click();

Clicking other cell's child element in Selenium WebDriver Java

What is the code to be used to click the "a" element by looking first for the "td" that contains certain texts?
<table>
<tbody>
<tr>
<td><a class="link">link</a></td>
<td>1st</td>
</tr>
<tr>
<td><a class="link">link</a></td>
<td>2nd</td>
</tr>
</tbody>
</table>
I used this code but it doesn't work.
driver.findElement(By.xpath("//td[contains(text(), '1st')]/following-sibling::a[#class='link']")).click();
Try this xPath //td[contains(text(), '1st')]/../td/a[#class='link'].
Your mistake comes from the axis "following-sibling". The tag a is not a sibling of the td tag. I use .. to go up, then select td again and then a.
I tested the xPath using http://www.xpathtester.com/xpath. It works. Beware that every browser comes with their own xPath implementation, therefore it could behave a bit differently.
However, as there is nothing exotic in the xPath expression, I don't expect any problem.

How can I insert a HTML tag before its parent tag using the Transformer from Genshi?

I need to modify the file table in my trac browser view by creating a class which implements the ITemplateStreamfilter class. I tried using the Transformer from genshi.filters.transform. My table looks like
<tbody>
<tr class="even">
<td class="name">
<a class="partent" title="Parent Directory" ..>..</a>
</td>
..
</tr>
..
</tbody>
I now need to insert a </td> tag just before the frist cell in the first row of the table. The problem is that I only can identify the position of column where I want to put the new cell befor by searching for the "Parent Directory" title: Transformer('//*[#title="Parent Directory"]'). How can I step one tag up than put the new cell before the first <td class="name"> tag?
I'm not THAT familiar with the support for XPATH of Transformer BUT:
What about
Transformer('(//td[*[#title="Parent Directory"]])[1]') and then using the before method?
As far as I understand, this should select the first td node with a child node with an attribute title="Parent Directory".
If you want to select any td with that kind of child node use
Transformer('//td[*[#title="Parent Directory"]]')
However, this only works if Transformer supports those XPATH expressions.
Edit 1
If you're sure, your td has an attribute class="name" you can also use Transformer('(//td[class="name" and *[#title="Parent Directory"]])[1]')