How to click the nearest link - java

Lets say we have a table of people. In each row there is a picture, a name, a city and some social buttons, like PM, add as friend, follow.
How can I "Add as friend" a certain person?
There are 10 people, there are 10 "Add as friend" buttons, and I have a name - lets say George Busch.
I don't know which place is his profile going to take out of those 10, when the page is generated, I just want to click the "add as friend" link that is NEAREST to George Busch.
EDIT: I will use the example code provided from the accepted answer, to demonstrate my case:
<table id="addfriendstable" class="colouredgrid">
<tr id="person65894" class="resultsrow odd">
<td>George Busch</td>
<td><button class="befriend">Add as friend</button></td>
</tr>
<tr id="person3244" class="resultsrow even">
<td>Jimmy Corker</td>
<td><button class="befriend">Add as friend</button></td>
</tr>
<tr id="person91236" class="resultsrow odd">
<td>Abraham Linton</td>
<td><button class="befriend">Add as friend</button></td>
</tr>
</table>
EDIT: This is my real-life example. I can't connect the xpaths right
These are the user's clickable name xpaths:
xpath=(//a[contains(text(),'Justin Timberlake')])[2]
//div[#id='main']/div/section/section/ul/li[2]/article/section/section/a
xpath=(//a[contains(#href, '/users/justin-timberlake')])[4]
//li[2]/article/section/section/a
and these are the different variants of the "Add as friend" button:
xpath=(//a[contains(text(),'Add as Friend')])[2]
//div[#id='main']/div/section/section/ul/li[2]/article/section/section/div/a
//a[contains(#href, '/users/1/friendships?friend_id=51c027d7f325db7ee7000032&origin=search')]
//li[2]/article/section/section/div/a

You can make an xpath which identifies the table cell containing the text 'George Busch', and then tracks over to the cell containing the button. This is concise and efficient.
Exactly how the xpath is constructed depends on your overall html structure, but I'll show you a simple worked example.
HTML
<table id="addfriendstable" class="colouredgrid">
<tr id="person65894" class="resultsrow odd">
<td>George Busch</td>
<td><button class="befriend">Add as friend</button></td>
</tr>
<tr id="person3244" class="resultsrow even">
<td>Jimmy Corker</td>
<td><button class="befriend">Add as friend</button></td>
</tr>
<tr id="person91236" class="resultsrow odd">
<td>Abraham Linton</td>
<td><button class="befriend">Add as friend</button></td>
</tr>
</table>
Building the xpath
The first part of the xpath is to uniquely identify the td cell with your text in it. For now, I'm assuming that you know for certain that the person's name won't show up anywhere else in the screen's html:
//td[text()='George Busch']
The next part of the xpath uses the double-dot .. notation to represent the parent, because we want to go back up the hierarchy one level to the tr table row:
//td[text()='George Busch']/..
And the next part of the xpath goes down the hierarchy a level to find the button; for now, I'm assuming that each row of the table has only one button:
//td[text()='George Busch']/../td/button
So the overall pattern is concentrating on two elements, the person name and the button; the xpath finds the person name first, then tracks back up the hierarchy as far as the common parent, then back down to the button.
Tweaking the xpath
Depending on your overall html structure, my example xpath might need changing. For example, maybe the screen has a number of different tables where the text 'George Busch' might occur? In that case, you need to uniquely identify the table, for example by using the id like this:
//table[#id='addfriendstable']//td[text()='George Busch']/../td/button
Or maybe the table has several buttons in each row? If so, we need to uniquely identify which button we want, for example by using the class:
//td[text()='George Busch']/../td/button[#class='befriend']
Firepath
I really recommend using Firepath for firefox - it's a great tool for checking that your xpaths are working. I've used it to verify the example xpaths in this answer.

Well this is a very common scenario when comes to working with grids. The best way to do this is by using xpath. The trick is to get the row which contains the name George Busch no matter where the row is in the grid. In the row click on the button. Will give a simple example using the grid in the following website.
http://demos.kendoui.com/web/grid/index.html
.The grid customer database there are many users. I will show the xpath which will get the age for person with first name Margaret. If you show the html probably something similar to this can be given. The xpath is as follows.
//tr[td[text() = 'Margaret']]/descendant::td[text()= '55']

Write a selector so that a findElements() will return 10 elements (one for each person)
On each element, do a element.getText(), and test to see if it contains George Busch.
If it does, then on the next element, do a element.findElement("") selector that will return the link, and click on it.

Related

read td class from url using java

hello i need little help reading website content
i want to read
<tr>
<td class="text-center"><strong>This Month</strong></td>
<td class="text-center">1194</td>
<td class="text-center">22</td>
<td class="text-center">7</td>
</tr>
i make it like this but it always return nothing
if (url.toLowerCase().contains("top100arena.com") && line.contains("<strong>This Month</strong></td><td class=\"text-center\">"))
return Integer.valueOf(line.split(">")[1].replace("</td", "").replace(",", ""));
if you are considering using third-party libraries, jsoup is a good idea.
https://jsoup.org/
using css / xpath selectors, you can indicate the element you are interested in, e.g.
//tr/td[contains (strong,.)]
will find all bold entries, then we can get the parent for that element, and read all the elements
http://xpather.com/
https://devhints.io/xpath
jsoup: How to select the parent nodes, which have children satisfying a condition

Thymeleaf - conditional rendering based on value of object property

<tr th:each="student: ${students}">
<td th:text="${student.id}" />
<td th:text="${student.name}" />
</tr>
I have 10 students with different names. I only want to render the whole table if there is AT LEAST 1 student with student.name == "Felix". Otherwise I donĀ“t want to render the table.
How can I do that?
In the controller which returns this template, check the list in Java. If you find "Felix".equals(student.name) then add a variable like 'isRenderTable' to the context and do a conditional on the table in Thymeleaf, like:
<table th:if="${isRenderTable}">...</table>
If you don't want to touch the server side code, then you can use Thymeleaf and JavaScript. Render the student list into JS, then use JS to perform the logical comparison you want, then render the table via JS.
Another way to do it is to render the student list into JS, and also render the table in Thymeleaf (and keeping the table hidden with CSS), then in JS if you detect the proper condition, change the CSS to show the table.
Below code should do the trick:
<table th:if="${not students.?[name == 'Felix'].isEmpty()}">
<tr th:each="student: ${students}">
<td th:text="${student.id}" />
<td th:text="${student.name}" />
</tr>
</table>

Selenium, Java. Need to select ancestor element inside table by Xpath

I have an HTML page containing the following code :
<table class="report" style="width:100%">
<tbody>
<tr>
<th/>
<th>Position Open
<br>
<span class="timestamp">27/7/2016 16:12:12</span>
</br>
</th>
<th>Position closed
<br>
<span class="timestamp">27/7/2016 16:12:42</span>
</br>
</th>
</tr>
<tr>
<td>
<span dir="ltr">EURJPY</span>
</td>
<td>116.098</td>
<td>116.156</td>
</tr>
</tbody>
</table>
On this page I have another table with the same class attribute "report" but only this table contains texts "Position Open" and "Position Closed".
I need to select elements containing the "EURJPY", "116.098" and "116.156" data.
These elements content is changing i.e. instead of "EURJPY" may appear "EURUSD" or "GBPCAD" etc.
I tried the following code:
driver.findElement(By.xpath("//span[text()='Position Open']/ancestor::table[#class='report'](//tr)[2]/td/span")).getAttribute("textContent");
to get the first required field text but got the Invalid selector error.
Your XPath is close but there were a couple issues.
//span[text()='Position Open']/ancestor::table[#class='report'](//tr)[2]/td/span
You are searching for a SPAN that contains the text 'Position Open' when in fact it is a TH that contains the text.
//th[text()='Position Open']/ancestor::table[#class='report'](//tr)[2]/td/span
(//tr) should be corrected to //tr
//th[text()='Position Open']/ancestor::table[#class='report']//tr[2]/td/span
What you want is the text contained in the TD, not the SPAN. If you pull the text from the TD you can get the text you want from all three elements. If you pull the SPAN, then you will also need to pull the last two TDs. This way is just simpler.
...and finally, the TH contains more than just the text you are looking for. Use .contains() to get a match.
//th[text()='Position Open']/ancestor::table[#class='report']//tr[2]/td
So we take that XPath and put it into Java code and we get the below.
List<WebElement> tds = driver.findElements(By.xpath("//th[contains(text(),'Position Open')]/ancestor::table[#class='report']//tr[2]/td"));
for (WebElement td : tds)
{
System.out.println(td.getText());
}
There can be issues matching the text sometimes, use contains instead, try this selector
//th[contains(.,'Position')]/ancestor::table[#class='report']//tr[2]/td/span
You can use this xpath to locate the 3 <td> tags you are interest in
//th[contains(text(),'Position Open')]/ancestor::table//tr[2]/td
Using it will give you list of three elements, you can extract the text from them
List<WebElement> tds = driver.findElement(By.xpath"//th[contains(text(),'Position Open')]/ancestor::table//tr[2]/td");
String currency = tds.get(1).getText(); // this will be EURJPY
tds.get(2).getText(); // 116.098
tds.get(3).getText(); // 116.156

Retrieving value of visible element using java

I have two elements with name price1 [BTW I know that having duplicate IDs is against standards, is this the same with NAME?]
<TR CLASS="Blocks" id="p_priceKILO" style="display: none ;">
<TD>Price:</TD>
<TD><INPUT TYPE="text" name="price1">$/kilo</TD>
</TR>
<TR CLASS="Blocks" id="p_pricePOUND" style="display: none ;">
<TD>Price:</TD>
<TD><INPUT TYPE="text" name="price1">$/pound</TD>
</TR>
Only one of these rows will be visible at one time (using javascript)
I use the following java code to retrieve price1
public PricePosition(HttpServletRequest request) {
this.price1=StringFunctions.StringToDouble(request
.getParameter("PRICE1"));
...
Is there any neat way to retrieve only the visible element?
I have a workaround - calling them price1a and price1b and retrieving the correct one based on my knowledge of which one is visible, but I wondered if there was another way.
You'll have to use JS again: when displaying a row, rename the inner corresponding input to displayedPrice for example, and get this parameter server-side.
When hiding a row, don't forget to rename it back.

Display more than one div or table content of same id from onchange value

I'd like to know if you can display more than one div or table content of same id from onchange value. Like if I select an option from drop down and it displays its content but i want to display another content from elsewhere in my page when same option is selected.
My code is as follows:
<select name="debitOrderType" id = "debitOrderType"
onChange="display(this,'BANK','CARD','INVOICE');">
<option>Please select...</option>
<option value="BANK" selected>Debit Order (Monthly)</option>
<option value="CARD">Credit Card (Monthly)</option>
<option value="INVOICE">Invoice (Yearly)</option>
</select>
Then when selecting Invoice from dropdown it displays the following:
<tbody id="INVOICE" style="display: none;">
<tr>
<td class="field">Thank you for selecting to pay yearly in advance. By doing so you
are receiving one month's free listing.
</td></tr>
</tbody>
But now i want to display the following ALSO when Invoice is selected but in another part of the page:
<tbody id="INVOICE" style="display: none;">
<tr><td height="5"></td></tr>
<tr><td align="right">This is your discounted yearly price</td></tr>
</tbody>
But only the first part is showing and not both. It looks like you can't display more than one content from same Id.
Hope you can help me?
Thanks in advance!
You mustn't define two elements with the same id in HTML, it's meant to be a unique identifier. Classes can be used multiple times, so use that!
First of all it is bed practice to assign same id to more than one element, although DOM will never find 2nd element of same id. Assign class to both table and make it visible on onChange event of combo box, then it will work.
If you want to display or apply css on single object then you should use ID. And if you want to display or apply css on multiple object then you should use CLASS.
In your example you should avoid ID and use class.
avoid this
id="INVOICE"
Use this
class="INVOICE"
Hope it will help you.

Categories