How do I find a button that is on the same line as "Lois" using XPath

<!DOCTYPE html> <html> <head> <style> table, th, td { border: 1px solid black; } </style> </head> <body> <h2>Add a border to a table:</h2> <table> <tr> <th>Firstname</th> <th>Lastname</th> </tr> <tr> <td>Peter</td> <td>Griffin</td> <td><button type="button">Click!</button></td> </tr> <tr> <td>Lois</td> <td>Griffin</td> <td><button type="button">Click!</button></td> </tr> </table> </body> </html> 
  • Find not a cell but a button with the name of the cell in the first column with the name Lois - Loligan
  • It seems to me that there is a lack of input conditions: 1) whether the dynamic structure of the document changes (the position of the table with data in the document) 2) whether the data structure in the table itself changes (or dynamic) (for example, the names will not be in the first but the second cell, or even in one line as in the other - in another) - lospejos

2 answers 2

A simple option is a table as in a 3-column picture, the search consists of two stages:

  • find the cell column that contains the name "Lois"

     .//tr/td[text()[.="Lois"]] 
  • We accept that the table structure is constant and we get the second relative element relative to the column "Lois" and its button

     .//tr/td[text()[.="Lois"]]/following-sibling::td[position()=2]/button 

The second option is if the length of the table is unlimited (except for the first and last names there will be a bunch of other parameters), but the "Name" will start the line and the "Button" will finish, we can take the last element that corresponds to the button:

  .//tr/td[text()[.="Lois"]]/following-sibling::td[last()]/button 

The most universal option , when we do not depend on the position of the name cell and the button

  .//tr[td[text()[.="Lois"]]]/td/button 

An even more universal option pushed the comment lospejos .

We take into account that the name "Lois" corresponds to the column "Firstname", and not to any other. We find the position of the header "Firstname" (position 1) using the query

  count(tr/th/text()[.="Firstname"]/preceding-sibling::*)+1 

and use it to search for the name "Lois" in the string

  .//tr[td[count(tr/th/text()[.="Firstname"]/preceding-sibling::*)+1][text()[.="Lois"]]]/td/button 

that, given the calculated count, for the machine looks like

  .//tr[td[1][text()[.="Lois"]]]/td/button 

that is, our element must meet two conditions - is under the heading "Firstname" and have the name "Lois"

  • The universal version, IMHO, is not so universal: for example, if the value of "Lois" is in the column with the last name :-) I do not criticize, I just clarify :-) - lospejos
  • @lospejos It does not make a difference, even in the growth column, the question is - "with a specific name in the column", the column contains "Lois", it means our client - while1pass
  • one
    @lospejos you made me find a more advanced solution - while1pass

TL; DR;

Find the button element:

 /html/body/table/tr[td[1]/text()='Lois' and td[2]/text()='Griffin']/td/button 

Find the cell element (with the button):

 /html/body/table/tr[td[1]/text()='Lois' and td[2]/text()='Griffin']/td 

I want to note that this answer assumes that the first cell of each row of the table contains the name, and the second cell contains the last name. If the table structure is dynamic, it is necessary to use a more intelligent search algorithm.

  • We can restrict ourselves to the condition tr [td [1] / text () = 'Lois', this is enough - while1pass
  • Did not help. And how to use the condition? - Loligan
  • By @Loligan, by condition, I mean expressions between [] -shells. for example, such an expression would give a similar result .//tr[td[[[> / text () = 'Lois' (black) / td / button. look below my solution, it covers many search cases - while1pass
  • @Loligan and how exactly "did not help"? Doesn't return the expected results? I tested on OxygenXML, I have correctly returned. Of course, if your document structure is no different - lospejos
  • @lospejos I think he just did the xpath so tr [td [1] / text () = 'Lois', and not in the expression - that didn’t help - while1pass