How can I find an element with XPath using its parent? - xpath

I need to get the "a" element inside a "td" element from a row in a table of several similar rows. The problem is I only have the name 'john'. How can I find john td -> get the parent "tr" -> and then get "a" in XPath?
Code example:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<table>
...
<tr id='1'>
<td name='john'>
</td>
<td>
<a id='clickable'/>
</td>
<td>
</td>
</tr>
...
</table>
</html>

I would write this XPath expression like this:
//td[#name="john"]/following-sibling::td[1]/a
This does:
//
from any depth
td
find a td element
[#name="john"]
with a name attribute equal to 'john'
/following-sibling::
now look among its following sibling elements
td
and find another td
[1]
get the first one
/a
and get its children that are a elements

How about:
//a[ancestor::tr[td/#name = 'john']]

What I would do :
//*[#name="john"]/../td/a/#id

Related

Find an element by text, get xpath and put in a list as every td is a unique element - selenium webdriver junit

I have a dynamically generated table with thead and tbody. Here is the example:
<tbody id="tableId" class="someclass1">
<tr id="rowId1" class="somesubclass">
<td id="item1" class="othersubclass">
<span class="attr">john Doe</span>
<td id="item2">
<span class="attr">55</span>
<td id="item3">
<span class="attr">5 street</span>
<td id="item2">
<span class="attr">cat</span>
<tr id="rowId2" class="somesubclass2">
<td id="item1" class="othersubclass2">
<span class="attr">joe smith</span>
<td id="item2">
<span class="attr">60</span>
<td id="item3">
<span class="attr">2 street</span>
<td id="item2">
<span class="attr">dog</span>
|joe doe|55|5 street|cat|
|joe foo|60|1 street|dog|
I would like to locate a row by text where the name is joe doe and put it into a list.
Locatior is working with this, but it is not a list.
#FindBy(xpath = "//tbody[contains(#id,'tableId')]/tr[td//text()[contains(.,'joe doe')]]")
private List<WebElement> list;
I got the list, but I cannot iterate over because everything has put into the first position like this:
list first element is: joe doe 55 5 street cat so this is the [0] element
How can I locate this row as a list where every td is a unique element in the list.
(iterate over, converting to string etc. is not a problem, just the locator.)
Thanks!
I don't understand what's for the -1. Anyway, here is the answer for others, hope this helps!
There is a good plugin for google kinda firepath: SelAssist, I use it to test my xpath locators.
The problem was that, td was missing. So the proper locator is
//tbody[contains(#id,'tableId')]/tr[td//text()[contains(.,'joe doe')]]/td
and it gives me list of elements, not only one.
Cheers!

Xpath to select next parent of the current node

if tr contains class="productnamecolor colors_productname" i want to select next tr which contains the price details. so i use :
.//a[#class="productnamecolor colors_productname"]/parent::node()/following-sibling::tr
But didn't work. What is wrong with this expression?
HTML :
<tr>
<td valign="top" width="100%">
Trouser Suspenders
</td>
</tr>
thanx in advance.
The parent of your <a> element is a td element, and the td element doesn't have a following-sibling - certainly not a following sibling that is a tr. If you want the next row in the table, use
.//a[#class="..."]/ancestor::tr[1]/following-sibling::tr[1]
or
.//tr[descendant::a/#class="..."]/following-sibling::tr[1]
If you want to select just next tr after <a class="productnamecolor colors_productname"> simply use following two ways :-
using following axis :
(.//a[#class="productnamecolor colors_productname"]/following::tr)[1]
using preceding axis :
(.//tr[preceding::a[#class="productnamecolor colors_productname"])[1]
Hope it helps...:)

XPath: Getting a node by attribute value of subnode

People, could you please help me with this XPATH. Lets say I have the following HTML code
<table>
<tr>
<td class="clickable">text</td>
<td>value1</td>
</tr>
<tr>
<td>value2</td>
<td>text</td>
</tr>
</table>
I need to build a XPath that will pick <tr>that have <td> with value text AND attribute class equals clickable.
I tried the following xpath:
//tr[contains(.,'text')][contains(./td/#class,'clickable')]
//tr[contains(.,'text')][contains(td/#class,'clickable')]
but none of those worked
Any help is appreciated
Thanks
You are almost there:
//tr[contains(td/#class,'clickable') and contains(td, 'text')]
Demo using xmllint:
$ xmllint input.xml --xpath "//tr[contains(td/#class,'clickable') and contains(td, 'text')]"
<tr>
<td class="clickable">text</td>
<td>value1</td>
</tr>
If you find tr with a td having value text and a td (maybe, another) with attribute class equals clickable, use answer of #alecxe.
If that is one td with two condition then
//tr[td[.='text' and #class='clickable']]

Finding first matching sibling element while traversing the DOM

I am trying to create an xpath expression that will find the first matching sibling 'down' the dom given an initial sibling (note: initial siblings will be Tom and Steve). For example, I want to find 'jerry1' under the 'Tom' tr. I have looked into the following-sibling argument, but I'm not sure that's the best approach for this? Any ideas?
<tr>
<a title=”Tom”/>
</tr>
<tr>
<a title=”jerry1”/>
</tr>
<tr>
<a title=”jerry2”/>
</tr>
<tr>
<a title=”jerry3”/>
</tr>
<tr>
<a title=”Steve”/>
</tr>
<tr>
<a title=”jerry1”/>
</tr>
<tr>
<a title=”jerry2”/>
</tr>
<tr>
<a title=”jerry3”/>
</tr>
following-sibling will work. This will select the a node with the title "jerry1":
//a[#title='Tom']/../following-sibling::tr/a
The /.. traverses up to Tom's parent <tr>, then following-sibling to the next <tr>, then finally the <a> node within that.
Following XPath worked for me:
(//a[#title='Tom']/parent::*/following-sibling::tr/a[#title= 'jerry1'])[1]
First matching a with title jerry1 following a tr with an a-child with title Tom.
Starting at a[#title='Tom'], going to the parent tr with /parent , selecting all following sibling tr-nodes with ::*/following-sibling::tr, that have an /a[#title= 'jerry1'] as child node. Because this would select 2 jerry1-nodes and the first jerry1 following Tom is searched, selecting the first one by wrapping the XPath with () and choosing the first match with [1].
The following XPath statement finds the first tr element that has an a with the #title "jerry1" that is a following-sibling of the tr element that has an a with the #title of "Tom"
//tr[a/#title='Tom']/following-sibling::tr[a/#title='jerry1'][1]

Xpath: howto return empty values

I have an Xpath like following:
"//<path to some table>/*/td[1]/text()"
and it returns text values of all non-empty tds, for example:
<text1>, <text2>, <text3>
But the problem is that between nodes, that contain mentioned values could be some empty tds elements:
What i want is to get result that contain some identifiers, that there is those empty values, for example:
<text1>,<>, <>, <text2>, <text3>, <>
or
<text1>,<null>, <null>, <text2>, <text3>, <null>
I tried to use next one:
"//<path to some table>/*/string(td[1]/text())"
but it returns undefined
Of course, I could just get whole node and then work with it in my code (cut all unnecessary info), but may be there is a better way?
html example for that case:
<html>
<body>
<table class="tablesorter">
<tbody>
<tr class="tr_class">
<td>text1</td>
<td>{some text}</td>
</tr>
<tr class="tr_class">
<td></td>
<td>{some text}</td>
</tr>
<tr class="tr_class">
<td>text2</td>
<td>{some text}</td>
</tr>
<tr class="tr_class">
<td>text3</td>
<td>{some text}</td>
</tr>
<tr class="tr_class">
<td></td>
<td>{some text}</td>
</tr>
</tbody>
</table>
</body>
</html>
Well simply select the td elements, not its text() child nodes. So with the path changed to //<path to some table>/*/td[1] or maybe //<path to some table>/*/td you will get a node-set of td elements, whether they are empty or not, and you can then access the string contents of each node (with XPath (select string(.) for each element node) or host environment method e.g. textContent in the W3C DOM or text in the MSXML DOM.). That way the empty strings will be included.
In case you use XPath 2.0 or XQuery you can directly select //<path to some table>/*/td/string(.) to have a sequence of string values. But that approach with a function call in the last step is not supported in XPath 1.0, there you can select the td element nodes and then access the string value of each in a separate step.
Do you mean you want only the td[1] with text and get rid of ones without text? If so, you can use this xpath
//td[1][string-length(text()) > 1]

Resources