How to find <span> Element within <tr> by XPath - xpath

My HTML Code looks like this:
<html>
<body>
<div>
</div>
<div>
<table>
<tbody id=a>
<tr>
<td>
<div>
<span>
some Text
</span>
</div>
</td>
</tr>
<tr>
<td>
<div>
<span>
some Text2
</span>
</div>
</td>
</tr>
<tr>
<td>
<div>
<span>
some Text3
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</body>
I'm trying to select each of the span elements by their text. I'm able to select the tbody by id. I Tried this:
tbody.FindElement(By.XPath(String.Format(".//span[contains(text(), {0}))]", &var)));
(var = somex0020Text)
but this always returns the first <span> element in my table.
I also tried:
tbody.FindElements(By.XPath(String.Format(".//span[contains(text(), {0}))]", &var)));
which returned a list containing every single <span> element in my table, and I don't know why.
I also don't understand why
tbody.FindElement(By.XPath(String.Format(".//span[text() = {0})]", &var)));
throws an Element not found Exception, when the contain method returns a <span> element with just the same text.

I tried by using xpath as:
.//span[contains(text(),'some Text')]
it is selecting all the 3 span.
so to this i have refer to parent element.
for 1st span: .//tbody[#id='a']//tr[1]//span[contains(text(),'some Text')]
for 2nd: .//tbody[#id='a']//tr[2]//span[contains(text(),'some Text')]
for 3rd: .//tbody[#id='a']//tr[3]//span[contains(text(),'some Text')]
through this I can select every span element individually.

You could use the jQuery to get all the span elements within "Table".
Example:
var items = $('table div span');
items.each(function (x) {
alert(items[x].innerHTML);
});

tbody.FindElement(By.XPath(String.Format(".//span[contains(text(), {0}))]", &var)));
(var = somex0020Text)
but this always returns the first Element in my table.
This is an expected behavior in Selenium. As i can see, there are 3 elements with the same xpath as mentioned in your code, in this case Selenium returns the first element.
tbody.FindElements(By.XPath(String.Format(".//span[contains(text(), {0}))]", &var)));
which returned a list containing every single Element in my table, and i dont know why.
This is also an expected behavior in Selenium. FindElements will return all the elements with the same xpath.
So change the value of var to some Text2 or some Text3 to locate the other two elements.
The following xpath will work for some Text2 :
.//span[contains(text(), 'some Text2'))]

Try with this Xpath $x("//tr//span[contains(.,'some Text')]")

For what I can see, you are having a trouble with the contains. All 3 spans are containing this 'some Text' portion.
If you want to check the entire string, you could use .//span[text()='some Text'].
Hope this helps, and have fun with web parsing!

Related

Unable to click on Select link present in last column of web table

I want to search Seller and have to click on select link for selected one. When I type seller name, it shows only record for selected seller.
I tried with following code, its not working. Can anyone please help
cy.get('input[name="search"]',{ timeout: 10000 }).type(this.data1.vehicle1_seller1)
//cy.wait(6000)
Cypress.config('defaultCommandTimeout', 10000);
cy.get('td[class="span-3"] div').each(($el, index, $list) => {
if ($el.text().includes('STB002')) {
// cy.contains("Select").eq(index).click()
cy.get('.span-1-5 > div > a > span').contains('select').eq(index).click({force:true})
}
}
this is the DOM structure >
<table>
<tbody>
<tr class="even">
<td class="span-3">
<div title="06V001">06V001</div> == $0
</td>
<td>
<div title="06 Vauxhall Ormskirk">06 Vauxhall Ormskirk</div>
</td>
<td class="span-1-5">
<div>
<a id="link57" href="./wicket/page?7-1.-seller-table-body-rows-10-cells-3-cell-link">
<span>select</span>
</a>
</div>
</td>
</tr>
<tr class="odd">
</tr>
<tr class="even">
</tr>
</tbody>
</table>
The HTML table is set out in rows and cells, exactly as you see it on the screen.
Your test is searching for the cell containing the text, but really you want to search for the row containing the text, then get the select button of that row.
The basic test would be
cy.contains('tr', 'STB002')
.within(() => {
// now inside the row
cy.contains('span', 'select').click()
})
The next problem is the car STB002 isn't on the first page, so you won't find it straight after loading.
Maybe use the search box to load that row (as you have in one screen-shot). I can't say what that code is, because the DOM picture doesn't include the search box.

Xpath to match specific text

I have this HTML structure:
https://imgur.com/a/8TevWtz
<tbody>
<tr data-drupal-selector="edit-strings-996" class="odd">
<td><div id="edit-strings-996-original" class="js-form-item form-item js-form-type-item form-type-item js-form-item-strings-996-original form-item-strings-996-original form-no-label">
<label for="edit-strings-996-original" class="visually-hidden">Source string (Built-in English)</label>
Search
</div>
</span></td>
<td><div class="js-form-item form-item js-form-type-textarea form-type-textarea js-form-item-strings-996-translations-0 form-item-strings-996-translations-0 form-no-label">
<label for="edit-strings-996-translations-0" class="visually-hidden">Translated string (EspaƱol)</label>
<div class="form-textarea-wrapper">
<textarea lang="es" data-drupal-selector="edit-strings-996-translations-0" id="edit-strings-996-translations-0" name="strings[996][translations][0]" rows="1" cols="60" class="form-textarea resize-vertical">Search</textarea>
</div>
</div>
</td>
</tr>
<tr data-drupal-selector="edit-strings-1176" class="even">
<td><div id="edit-strings-1176-original" class="js-form-item form-item js-form-type-item form-type-item js-form-item-strings-1176-original form-item-strings-1176-original form-no-label">
<label for="edit-strings-1176-original" class="visually-hidden">Source string (Built-in English)</label>
Search page
</div>
I need a Xpath that I can find only the exact text "Search". I cannot use contains() because it will return all rows with this word, I need only the row with "Search" word only.
My knowledge of Xpath is not great, so I tried many things like:
//tbody/tr/td/div[.='Search']
//tbody/tr/td/div[normalize-space(.)='Search']
//tbody/tr[1]/td/div/. -> This one works but I cannot pass the tr[1] because I'll use this xpath in an automation and the text I want is not always in the first row, so I need to find by Text and not by Index.
The problem is that all texts have these whitespaces and it makes it worse for me to make it work.
Text content of target div node is not just "Search", but "Source string ... Search", so you can try
//div[normalize-space(text()[2])='Search']
Assuming you're looking for the div which has text containing the string Search, this should work:
//tbody/tr/td/div[contains(., 'Search')]
It's a bit dirty in that it would also detect Search anywhere under the div, e.g. including in the label's text, if applicable.

XPATH Firebug filter does not filter as expected

Basically I have a list of presidents and I am only interested in the Nixon link and not Clinton or Obama.
What I find is that filtering as I have done returns the correct number of presidents (ie 1 in this case) but returns ALL of the a links instead of just the one for Nixon.
HTML:
<div class="headlineBlock">
<h2>Obama</h2>
<p class="tudor"><strong>Conditions:</strong> Always sunny </p>
<table class="resultGrid"><tr> <td class="first">
<h4><a href="http://www.thelinkiwant.com?params" title="Click to view result"</a></h4>
<div class="headlineBlock">
<h2>Nixon</h2>
<p class="nixon"><strong>Conditions:</strong> Sometimes late </p>
<table class="resultGrid"><tr> <td class="first">
<h4><a href="http://www.thelinkiwant.com/?params" title="Click to view result"</a></h4>
<div class="headlineBlock">
<h2>Clinton</h2>
<p class="tudor"><strong>Conditions:</strong> Never rainy </p>
<table class="resultGrid"><tr> <td class="first">
<h4><a href="http://www.thelinkiwant/?params" title="Click to view result"</a></h4>
XPATH:
$x("//div[#class='headlineBlock']/h2[not(contains('|Clinton|Obama|',concat('|',.,'|') ))]//../../table/a/#href")
There are several issues with your example.
There brackets missing after ever single "Click to view result", your "headlineBlock" divs and tables aren't closed, etc. So first you should make sure that your data is well formatted.
W3C's Xml Validator can help with that
Your XPath looks mostly ok, I think the issue is with the // at the end - they are a bit too early. Try this instead:
//div[#class='headlineBlock']/h2[not(contains('|Clinton|Obama|',concat('|',.,'|') ))]/..//a/#href
//div[#class='headlineBlock']
All divs of class headlineBlock ...
/h2[not(contains('|Clinton|Obama|',concat('|',.,'|') ))]
... that don't contain certain terms.
/..
Up one level (now we are at div headlineBlock again)
//a
Any direct descendants of element type a
/#href
H-Ref Attribute

XPATH for tr that has multiple text's in side it

I need XPATH for <tr> that contains text 'abc' in second <td> and text 'xyz' in third <td>
Tried but no luck.
final String XPATH = "//tr[td[contains(.,'abc')] and td[contains(.,'xyz')]";
Your expression actually almost selects what you want (once you fix the missing last ]). You just need to specify positions of the <td> elements.
//tr[td[2][contains(.,'abc')] and td[3][contains(.,'xyz')]]
For the following XML document:
<document>
<table>
<tr>
<td>foo</td>
<td>abc</td>
<td>xyz</td>
</tr>
<tr>
<td>foo</td>
<td>bar</td>
<td>xyz</td>
</tr>
</table>
</document>
this returns a node-set with the first <tr> element of the document in document order.

How to click on the table cell for particular text

The following is the DOM details:
<div id: "abc_440"
<table class = "listtable" >
<tbody>
<tr>
<td id = "someid" >
<td class = 'someclass_item"> This is Text </td>
<td class = 'someclass_button">
< a > Add </a>
</td>
</tr>
</tbody>
</table>
</div>
I need to click on 'Add' for particular text at "This is Text". I have to use div with ID (abc_440)to locate the corresponding table as there are may divs with this same dom layout. but index at div ID (for example 440) keeps changing to random number. How do I handle it in general ?
Please help.
I think that what you want to do is very similar to the previous Watir question.
Given that the id is randomly generated, it does not sounds like a good way of finding the link. You will likely need to use the text of the same row.
Assuming that the "This is Text" is unique (as you said you want to find the Add link for it), you can find that td, go to the parent row and then get the link.
b.td(:text => 'This is Text').parent.link.click
If you need to ensure that the text is in the second column, then you can do:
b.trs.find{ |tr|
tr.td.exists? and tr.td(:index => 1).text == 'This is Text'
}.link.click
The tr.td.exists? is added in case some of your rows do not have any tds (example a header row), which would cause an exception when checking the second criteria.
Don't mix quotes in HTML tags. id: doesn't work. <td>s should rarely be empty. The Add button should be a button, not an <a>nchor element. Buttons only work in <form>s.
<form id="abc_440" action='someURI'> <!-- The handler for the button. -->
<table class="listtable">
<tbody>
<tr>
<td id = "someid">
<!-- What goes here? -->
</td>
<td class='someclass_item'>
This is Text
</td>
<td class='someclass_button'>
<button name='add'>Add</button>
</td>
</tr>
</tbody>
</table>
</form>
You should be able to find the button through its name attribute, add, and through the form's id attribute, abc_440. Who generates the ids?
Once you have the problem of finding the add button solved, and figuring out where the form's id comes from, please then stop using tables for formatting. There's no need for that. Learn about <form>s, <fieldset>s, <legend>s, and <label>s. I doubt you need the *some_id* part, the text part should probably be a <label>, and you can use CSS to format your <label>s as:
label {
width: 150px;
float: left;
}
fieldset p {
clear: left;
}

Resources