I have a table containing tds like the one below.
Im trying to get a hold of the href-part only.
Now i got something like this:
var aTags = htmlDocument.DocumentNode.SelectNodes("//td//a[#href]");
It seems to be returning all the info in the td. How can I specify that I only want that href? There are many similar questions here but I cant seem to get it to work.
<tbody>
<tr>
<td colspan="1" rowspan="1">
<a shape="rect" id="ctl00_mainCPH_ResultListUC_ResultList_ctl04_hlRubrik" href="/sitevision/proxy/4.38a41afd11d99fbdb65800016.html/svid12_38a41afd11d99fbdb65800021/-123388378/Standard/Platsannonser/VisaFritextAnnonser.aspx?ids=2499859&q=s%28sn%28systemutvecklare%29sida%281%29ar%2820%29%29" style="display:inline-block;width:160px;">Systemutvecklare</a>
</td>
</tr>
</tbody>
. Every objects has for example an outerHtml-property looking like the a tag above,
what I need is yo get the hrefs and collect sthem in a list of strings..
The image below shows that the value i want actually exists in the objects im getting, i want the value of the hrefs...
EDIT:
I seem to be able to get the innerhtml like this:
var bTags = htmlDocument.DocumentNode.SelectNodes("//td//a/#href").Select(o => o.InnerHtml).ToList();
But I still dont know how to get the hrefs...
Your XPath will get you all a elements that have an attribute named href. To get the attribute itself, you need to use //td//a/#href.
This code seems to do what i wanted:
var bTags = htmlDocument.DocumentNode.SelectNodes("//td//a/#href").Select(o => o.Attributes["href"].Value).ToList();
Related
I've been strugguling to select a specifc node.
My query consists of two operations. First I need to get the position of a node using this:
count((//th[text()="TEST"])[1]/preceding-sibling::*)+1
and then I do this
(//th[position() = count((//th[text()="TEST"])[1]/preceding-sibling::*)+1])
When I test this query on chrome, it doesn't work. but when I execute them separately it works. Any idea what is wrong ?
Here is the HTML code:
<tbody>
<tr>
<th>TEST</th>
<th>TVA réduite<sup>(2)</sup></th>
<th>Prix TVA 20%</th>
<th>Surface</th>
<th>Etage</th>
<th>Orientation</th>
<th>Cave</th>
</tr>
<tr data-lot-id="0098__981104102">
<td>My Value</td>
<td>462 000€</td>
<td><strong>525 500 €</strong></td>
<td>100.23m²</td>
<td>10</td>
<td>Est</td>
<td>Non</td>
</tr>
</tbody>
I believe you are trying to get the value based on the header.
Scenario 1: Get td value based on th (header)
//td[position()=count(//th[normalize-space(.)='TEST']/preceding-sibling::th)+1]
Screenshot:
Scenario 2: Select the header based on the header text position(you don't need such a complex xpath for this simple though ;-) )
//th[position()=count(//th[normalize-space(.)='TEST']/preceding-sibling::th)+1]
Screenshot:
This is my html code:
<tr>
<th class="left_cont"><strong>Hello world</strong></th>
<td class="right_cont padding_left16px"><strong>Hi There</strong></td>
</tr>
Now to select the text Hellow world i used.
//strong[contains(text(),'Hello world')]
Works fine for me.
Now I need to select the text Hi there relatively to the hello world text.
I need to do something like this but I can't figure out.
//strong[contains(text(),'Hello world')]/following-sibling::strong
Doesn't work out for me.
Elements with sibling relations are parent of <strong> instead of <strong> it self, so you can try this way :
//*[strong[contains(.,'Hello world')]]/following-sibling::*[strong]/strong
Or if you are sure parents involved are always <th> and <td> :
//th[strong[contains(.,'Hello world')]]/following-sibling::td[strong]/strong
2nd "strong" element is not actually sibling of the first one. But wrapping "td" elements are siblings. So you could probably use
//strong[contains(text(),'Hello world')]/../following-sibling::td/strong
I am newbie in XPath. Can someone explain how to resolve this problem:
<table>
<tr>
<td>
<table>
<tr>
<td>
<table>
<tr>
<td>Label</td>
<td>value</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
I try to get <tr> which contains Label value, but it does not work for me,
Here is my code :
//td[contains(.,'Label')]/ancestor::tr[1]
Desired result:
<tr>
<td>Label</td>
<td>value</td>
</tr>
Can someone help me ?
This expression matches the tr that you want:
//tr[contains(td/text(), 'Label')]
Like yours, this starts by scanning all tr elements in the document, but this version uses just a single predicate. The td/text() limits the test to actual text nodes which are grandchildren of the row. If you just used td, then all of the td's descendant text nodes would be collected and concatenated, and the outer tr would match.
UPDATE: Also, for what it's worth, the reason your expression isn't working is that the ancestor axis returns elements in document order, not "outward" from the point of the context node. This is something I've run into myself, as it is somewhat unintuitive. To make your approach work, you would need to say
//td[contains(.,'Label')]/ancestor::tr[last()]
instead of
//td[contains(.,'Label')]/ancestor::tr[1]
I had the same issue, except that the text 'Label' was sometimes in a nested span, or even further nested in the td. For example:
<td><span>Label</span></td>
The previous answer only finds 'Label' if it is in a text element that is a direct child of the td. This issue is a bit harder because we need to search for a td that contains the text 'Label' in any of its children. Since the tds are nested, all tds qualify as having a descendant that contains the text 'Label'. So, the only way I found to overcome this is to add a check that makes sure that the td we select does not contain a td with the search text.
//td[contains(., 'Label') and not(.//td[contains(., 'Label')])]/ancestor::tr[1]
This says give me all of the tds that have a decedent text containing 'Label', but exclude all tds that contain a td that has a decedent text containing 'Label' (nesting ancestors). This returns the child most td that contains the text. Then you can go back to the tr that contains this td using ancestor.
Also, if you just want the lowest table that contains text use this:
//table[contains(., 'Label') and not(.//table[contains(., 'Label')])]
or you can select the tr directly:
//tr[contains(., 'Label') and not(.//tr[contains(., 'Label')])]
This seems like a common problem, but I didn't see a solution anywhere. So, I decided to post to this old unanswered question in hopes that it helps somebody.
Please take a look at the snippet of html below:
<tr class="clickable">
<td id="7b8ee8f9-b66f-4fba-83c1-4cf2827130b5" class="clickable">
<a class="editLink" href="#">Single</a>
</td>
<td class="clickable">£14.00</td>
</tr>
I'm trying to assert the value of td[2] when td[1] contains "Single". I've tried assorted variants of:
//td[2][(contains(text(),'£14.00'))]/../td[1][(contains(text(),'Single'))]
I've used similar notation elsewhere successfully - but to no avail here... I think it's down to td[1] having the nested element, but not sure.
Can someone enlighten as to what I'm getting wrong? :)
Cheers!
What about:
//tr[contains(td[1], "Single")]/td[2]
First select the <tr> containing the <td> matching the text, and then select td[2].
Then,
contains(//tr[contains(td[1], "Single")]/td[2], "£14.00")
should return True.
Or, closer to the expression you tried, you could test if this matches:
//tr[contains(td[1], "Single")]/td[2][contains(., "£14.00")]
See #JensErat's answer to find xth td with td contains in same tr xpath python .
Why not make it simple on yourself, do the if statement in your code. Psuedocode:
Select the top level tr.
Find first td within tr, check to see if it contains Single.
If it does, assert that it contains £14.00
Alternatively, you could just get the text of the top level tr and perform the checks on that text.
Problem:
Given a table, a specific piece of content should appear in the same column as a specific header.
Clarification:
I can not test the column position numerically, or at least I can't hardcode it that way, since the number of columns can change based on various other conditions and I don't want to make my test that fragile.
Example:
Name || Phone Number || Address
==============================================================
... || ... || ...
Joe || 555-787-7878 || 42 Nowhere Lane, Mulberry, California
... || ... ||
With the code looking like so:
<table>
<tr>
<th>Name</th>
<th>Phone Number</th>
<th>Registered</th>
<th>Address</th>
</tr>
<tr>
...
</tr>
<tr>
<td>Joe</td>
<td>555-377-7347</td>
<td>Yes</td>
<td>42 Nowhere Lane1, Mulberry1, California</td>
</tr>
<tr>
<td>Jerry</td>
<td>555-787-7878</td>
<td>Yes</td>
<td>50 Nowhere Lane, Mulberry, California</td>
</tr>
<tr>
<td>Tom</td>
<td>555-678-0987</td>
<td>No</td>
<td>43 Nowhere Lane2, Mulberry2, California</td>
</tr>
<tr>
...
</tr>
</table>
Scenario:
I want to insure the correct address (42 Nowhere...) appears in the column with the header "Address".
How can I do this?
The solution might be as simple as a decent xpath query, to be honest, perhaps I don't even need anything particularly "Capybara" related!
I came across similar one, but here I need to check whether 'Jerry' registered or not. Please help me how can i automate using ruby/capybara
Thanks in Advance
I think #Snekse is very close. Here are some expressions that have been tested. The following returns the table cell corresponding to the th whose value is Address:
/table/tr/td[(count(../../tr/th[.='Address']/preceding-sibling::*)+1)]
This can be used to get the value of the cell:
42 Nowhere Lane, Mulberry, California
...which you could then use to perform the final test:
/table/tr/td[(count(../../tr/th[.='Address']/preceding-sibling::*)+1)]
[.='42 Nowhere Lane, Mulberry, California']
This will return the cell itself, if the addresses match. It will return an empty node-set, which will evaluate to false in a boolean context, if no such node exists.
You probably also need to specify the row you're testing, which can be done with a slight modification to the start of the expression:
/table/tr[$n]/<rest_of_expression>
...where $n is the index of the row to select.
I would think you would first have to get the position of Address, then use that information to get the value from the data table.
So something like:
var x = count(/table/tr/th[.='Address']/preceding-sibling::*)+1.
var address = /table/tr/td[position()=${x}]
Or combine it into something like:
/table/tr/td[position()=(count(/table/tr/th[.='Address']/preceding-sibling::*)+1.)]
NOTE: I didn't run these statements, so I have no idea if they are valid xpath syntax or not, but it should be close enough to get you there.
REFERENCE: Find position of a node using xPath