find element inside element

55 views
Skip to first unread message

Idan Shay

unread,
Sep 28, 2017, 9:15:16 AM9/28/17
to webdriver
Hi,

I have table that I find it by id.
WebElement table = driver.findElement(By.id("tableId");

After that I make findElements 
List<WebElement> rows = table.findElements(By.cssSelector("tbody tr");

It return also the header meaning the tr under thead.

When I change it as below it does work.
List<WebElement> rows = table.findElements(By.cssSelector("tbody > tr");

The table is inside the body of another table so looks like it find all tr under table (that include the th) and are on any tbody even it not under the table.


Is this the expected behaviour ?

Thanks

darrell grainger

unread,
Sep 29, 2017, 9:36:14 AM9/29/17
to webdriver
Short answer, this is behaving as expected. This is CSS and not really a Selenium/WebDriver thing.

If the structure of the HTML is:

<table id='tableId'>
  <tbody id='tbody1'>
    <tr id='tr1'>
      <td>
        <table id='table2'>
          <tbody id='tbody2'>
            <tr id='tr2'>
              ...
            </tr>
          </tbody>
        </table>
      </td>
    </tr>
  </tbody>
</table>

then:

WebElement table1 = driver.findElement(By.id("tableId"));
List<WebElement> rows = table1.findElements(By.cssSelector("tbody tr"));

This will search EVERYTHING under TABLE with id='tableId' that has TR with a TBODY somewhere above it. So tr1 would be a match BUT tr2 would also be a match. The second TR matches two ways. The CSS selector "tbody tr" would match "tbody#tbody2 tr#tr2" but it would also match "tbody#tbody1 tr#tr2". Essentially, in CSS the "element1 element2" means that element2 is a child of element1. It could be an immediate child, a grandchild, a great grandchild, etc.. If you want the rows of ONLY the first TBODY then you  need to use "tbody#tbody1>tr". This will match only the TR which are immediate children of tbody#tbody1. If you tried using "tbody>tr" then it is going to match the rows in the first table and the second table.

If you have no way to differentiate between tbody1 and tbody2 then you might have to use "#tableId>tbody>tr". This will say give me all the TR immediately under a TBODY and a TBODY which is immediately under the first table. You cannot do this in two parts.

w3schools has a pretty good tutorial and reference section on this stuff. Here is the reference: https://www.w3schools.com/cssref/css_selectors.asp.

Darrell
Reply all
Reply to author
Forward
0 new messages