How to specify Xpath that return whole table without last row? - xpath

Here is the code of a table. I need to extract whole table without last row.
Whole table:
<table class="product-content__table">
<tr><th class="product-content__th">Состав</th><td>нержавеющая сталь, натуральная кожа </td></tr>
<tr><th class="product-content__th">Ширина</th><td>2 см</td></tr><tr><th class="product-content__th">Цвет</th><td>серый </td></tr>
<tr><th class="product-content__th">Страна производства</th><td>Россия </td></tr><tr><th class="product-content__th">Сезон</th><td>Мульти </td></tr>
<tr><th class="product-content__th">Коллекция</th><td>Весна-лето </td></tr>
<tr><th class="product-content__th">Артикул</th><td itemprop="sku">RO003DMCMA98</td></tr>
</table>
I need to extract whole table without this row:
<tr><th class="product-content__th">Артикул</th><td itemprop="sku">RO003DMCMA98</td></tr>

I need all tags including table tag.
XPath can only select nodes that are present in your input. If there is a table element in your input with five rows, and you want a table element with four rows, then there is no such table element in your input so you cannot select it with XPath. If you want to get a node that differs from any node in your input, you need XSLT or XQuery.

<td> is sibling of <th> not child so you don't actually need th in your xpath. And you want to filter out the last tr within the same table instead of filtering out the last td within the same tr :
//table[#class="product-content__table"]//tr[position() < last()]/td
remove trailing /td if you want to get list of <tr> instead of <td>.

This works:
//table//tr[position()<last()]

Related

Cypress - click hyperlink on row based on value of two cells

Trying to get a Cypress script to click a hyperlink based on two values - the text of the hyperlink in column 1 and the value of the cell in the second column:
<tbody>
<tr>
<td>Anything</td>
<td>Casualty</td>
</tr>
<tr>
<td>Declined Prospect</td>
<td>Casualty</td>
</tr>
<tr>
<td>Declined Prospect</td>
<td>Package</td>
</tr>
<tr>
<td>Declined Prospect</td>
<td>Casualty</td>
</tr>
<tr>
<td>Irrelevant</td>
<td>Package</td>
</tr>
</tbody>
cy.get('a').contains('Declined Prospect').click()
fails because there's more than one hyperlink with that value. The id is not useful because it's dynamic.
In the example above, I want to click Declined Prospect when the second column is Casualty (but the order of the rows may vary and values in the first and second column are repeated - but only once for the combination).
Any thoughts?
The trick is to target <td>Casualty</td> then click the preceding <td><a>.
There are quite a few ways to get to sibling elements, the simplest in this case is prev().
cy.contains('td', 'Casualty') // target the 'marker' element
.prev() // move to the previous sibling
.click()
Approach from row and move inwards
To target a row with a specific combination of text in some of it's cells, just concatenate the text and use contains().
cy.contains('tr', 'Declined Prospect Casualty') // target unique text within children
This even works when there are other cells with text that's not relevent to the search, e.g
<tr>
<td>Declined Prospect</td>
<td>Casualty</td>
<td>Irrelevent text here</td>
</tr>
Then you can walk down the HTML tree,
cy.contains('tr', 'Declined Prospect Casualty') // target unique text within children
.find('td a') // descendant of previous subject
.click()
I think this can be useful: https://github.com/cypress-io/cypress-xpath
You can create selectors in xpath instead of css and in xpath you can search tree by text. e.g:
cy.xpath("//text() = 'Declined Prospect'")
==================================Edited====================
You can merge couples of xpatch selectors: it will looks like this //tr[td='Casualty']/td/a
Playgroud

How do you select two different tags via xpath, both at different levels, when one of them is optional

I have a situation where the data is a mix of these format on the same page. In other words, some rows will show up as:
some lengthy XPATH_X uptill here:
<td/>
<td>
I Need this element td
</td>
<td/>
<td/>
<td/>
<td/>
and a few other rows will show in this format:
the same lengthy XPATH_X uptill here:
<td/>
<td>
<span>
I Need this element span
</span>
</td>
<td/>
<td/>
<td/>
<td/>
Please note that there are no differentiating attributes for each of the td tags. I need to select the second row (td) in both the cases.
I'm trying to catch both of the elements using the following xpath:
XPATH_X/*[self::td[position()=2] or self::td[position()=2]/span]
I tried this out on the page but for some reason it doesn't select anything.
Can someone please help me out with this? I've spent more than 2 hours on this already.
You should try XPATH_X/td[2]//text() to retrieve the text whether it's at the root of the td or in a child tag
You can test it here ; in this test I retrieve three results :
the text inside a span inside a td
the text at the root of a td
both the texts at the root of a td and inside the enclosed span (if this doesn't work for you and the text of the td should be retrieved only if there's no span, use XPATH_X/td[position()=2 and not(./span)]/text() | XPATH_X/td[2]/span/text() instead)
To retrieve the elements containing text nodes rather than the text node themselves, you can use the following :
XPATH_X/td[2]//self::node()[text()]

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...:)

How do I get the value inside a <td> tag with xpath/htmlwebunit

I am trying to create a Java Application that retrieves information from a webpage. This is part of the code I am trying to access the value in the 1st td tag in the 2nd tr tag:
<TABLE CLASS="datadisplaytable" width = "100%">
<TR>
<TD CLASS="dddead"> </TD>
<TH CLASS="ddheader" scope="col" ><SPAN class="fieldlabeltext">Capacity</SPAN></TH>
<TH CLASS="ddheader" scope="col" ><SPAN class="fieldlabeltext">Actual</SPAN></TH>
<TH CLASS="ddheader" scope="col" ><SPAN class="fieldlabeltext">Remaining</SPAN></TH>
</TR>
<TR>
<TH CLASS="ddlabel" scope="row" ><SPAN class="fieldlabeltext">Seats</SPAN></TH>
**<TD CLASS="dddefault">46</TD>**
<TD CLASS="dddefault">46</TD>
<TD CLASS="dddefault">0</TD>
</TR>
This is what i have right now but this only returns the class of the td tag and not the value inside it:
List<?> table = page.getByXPath("//table[#class='datadisplaytable'][1]//tr[2]/td");
How would I go about getting the value of the td tag and not its properties?
edit: The code above returns this:
HtmlTableDataCell[<td class="dddefault">]
I am trying to create a Java Application that retrieves information from a webpage. This is part of the code I am trying to access the value in the 1st td tag in the 2nd tr tag:
Assuming that the document is as shown in the question (TABLE is the top element),
Use:
/TABLE/TR[2]/TD[1]/text()
This selects any text-node child of the first TD child of the second TR child of the top element TABLE.
In case the table is buried in the XML document, but can be uniquely identified by its CLASS attribute, use:
//TABLE[#CLASS='datadisplaytable']/TR[2]/TD[1]/text()
This selects any text-node child of the first TD child of the second TR child of any (we know thre is only one such) element TABLE in the XML document, such that the string value of its CLASS attribute is the string 'datadisplaytable'.
Finally, if even worse, there could be many TABLE elements whose CLASS attribute's value is 'datadisplaytable', and we want to select in the first such table, use:
(//TABLE[#CLASS='datadisplaytable'])[1]/TR[2]/TD[1]/text()
for getting the text content from an element there is an xpath function called "text()" which you can use.
Element containing text 't' exactly //*[.='t']
Element <E> containing text 't' //*[.='t']
<a> containing text 't' //a[contains(text(),'t')]
<a> with target link 'url' //a[#href='url']
Link URL labeled with text 't' exactly //a[.='t']/#href
If you are also using JwebUnit, there is a method "getElementTextByXPath" which can also be used to get the text.
net.sourceforge.jwebunit.junit.WebTestCase
getElementTextByXPath
public String getElementTextByXPath(String xpath)
Deprecated.
Get text of the given element.
Parameters:
xpath - xpath of the element.
for (int i = 1; i != 6; i++) {
String result = getElementTextByXPath("//td["+i+"][text()]");
System.out.println("The Content of TD is " +result);
}

XPath matching text in a table - Ruby - Nokigiri

I have a table that looks like this
<table cellpadding="1" cellspacing="0" width="100%" border="0">
<tr>
<td colspan="9" class="csoGreen"><b class="white">Bill Statement Detail</b></td>
</tr>
<tr style="background-color: #D8E4F6;vertical-align: top;">
<td nowrap="nowrap"><b>Bill Date</b></td>
<td nowrap="nowrap"><b>Bill Amount</b></td>
<td nowrap="nowrap"><b>Bill Due Date</b></td>
<td nowrap="nowrap"><b>Bill (PDF)</b></td>
</tr>
</table>
I am trying to create the XPATH to find this table where it contains the test Bill Statement Detail. I want the entire table and not just the td.
Here is what I have tried so far:
page.parser.xpath('//table[contains(text(),"Bill")]')
page.parser.xpath('//table/tbody/tr[contains(text(),"Bill Statement Detail")]')
Any Help is appreciated
Thanks!
Your first XPath example is the closest in that you're selecting table. The second example, if it ever matched, would select tr—this one will not work mainly because, according to your example, the text you want is in a b node, not a tr node.
This solution is as vague as I could make it, because of *. If the target text will always be under b, change it to descendant::b:
//table[contains(descendant::*, 'Bill Statement Detail')]
This is as specific, given the example, as I can make:
//table[tr[1]/td/b['Bill Statement Detail']]
You might want
//table[contains(descendant::text(),"Bill Statement Detail")]
The suggested codes don't work well if the match word is not in the first row. See the related post Find a table containing specific text

Resources