Xpath to match specific text - xpath

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.

Related

Mailchimp address field in update form (advanced customiser)

I'm creating a custom update form and I want to display address information using MERGE tags.
I can find no information on how to display the Address subfields (Address 1, Address 2, City, etc.). I thought it might be along the lines of
value="*|MERGE3[addr1]|*"
e.g.
<tr>
<td align="right" class="formLabel">Address</td>
<td align="left">
<div class="field-wrapper">
<div class="addressfield">
<span class="subfield addr1field">
<label for="MERGE3-addr1"></label>
<input type="text" id="MERGE3-addr1" name="MERGE3[addr1]" maxlength="70" value="*|MERGE3[addr1]|*" placeholder="" class="av-text">
</span>
....
But this literally prints
value="|MERGE3[addr1]|"
in the update form field for Address 1. Can anyone help? It would be useful to know if it's even possible.

How to identify dynamically generated image id's in a table row by using nightwatch JS

I have a table in that each row have some information. In one of the rows, images are available and also they are clickable. I need to click one of the image which has dynamic id.
Please refer below source code
<tr id="tblRow_2">
<td height="25" colspan="8" style="border: none; text-align: right">
<input id="PPPayNow_0" type="image" src="/Client/images/paynowprepay.gif" onclick="pppayClick(0,35);"/>
<input id="PayNow_0" type="image" src="/Client/images/paynow.gif" onclick="payClick(0,35);" alt=""/>
</td>
<td></td>
<td id="paymentTotal_0" style="text-align:right; font-size:medium; font-weight:bold; color:Black; border:none"></td>
I have tried CSS selectors & x-path but no luck.
Presuming the onclick attribute values are constantly- they are js functions after all, so should be, this is how you can select the 1st input:
//td/input[starts-with(#onclick, "pppayClick")]
And this is for the 2nd:
//td/input[starts-with(#onclick, "payClick")]
You could do the same with the id attribute, if only the prefixes (the _0 part) change.
I solved this problem by using X-Path preceding siblings and x-path string functions for preceding Axes i.e. number string-length(string?) it returns the number of characters in the string . number string-length(string?) => this function I used for identifying input tag which will be enable after clicking checkbox.
solution is :
browser.useXpath().click('//*[#id="tableId"]/tbody/tr/td[3][string-length(text()) > 0]/preceding::td[2]/input[starts-with(#id, "PayNow")]');

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

How to find <span> Element within <tr> by 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!

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