16

I want to fetch data from tables in UI. I know about looping through rows and columns using "tr" and "td". But the one the table I have is something like this:

<table>
 <tbody>
  <tr><td>data</td><th>data</th><td>data</td><td>data</td></tr>
  <tr><td>data</td><th>data</th><td>data</td><td>data</td></tr>
  <tr><td>data</td><th>data</th><td>data</td><td>data</td></tr>
 </tbody>
</table>

How can I make my code generic, so that the occurrence of "TH" in middle can be handled. Currently, I am using this code :

// Grab the table
WebElement table = driver.findElement(By.id(searchResultsGrid));

// Now get all the TR elements from the table
List<WebElement> allRows = table.findElements(By.tagName("tr"));
// And iterate over them, getting the cells
for (WebElement row : allRows) {
 List<WebElement> cells = row.findElements(By.tagName("td"));
 for (WebElement cell : cells) {
 // And so on
 }
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Sky
  • 215
  • 1
  • 3
  • 11

8 Answers8

18

You could look for all children of tr element without differentiating between td and th. So instead of

List<WebElement> cells = row.findElements(By.tagName("td"));

I would use

List<WebElement> cells = row.findElements(By.xpath("./*"));
amurra
  • 15,221
  • 4
  • 70
  • 87
JacekM
  • 4,041
  • 1
  • 27
  • 34
  • 1
    But this will give all children including links , or input etc inside – Sky May 17 '12 at 15:29
  • Not really. My example would return only first-level children. This means only tr and th tags (referring to example). Elements between and (in other words anything from "data" from your example) will **not** be returned. – JacekM May 17 '12 at 15:59
  • @Sky - The supplied xpath will only get children, not descendants. – Sam Woods May 17 '12 at 16:00
  • @JacekM, how about if one needs to return children at all levels and not just first-level. For the reply above, +1 for sure. – anujin Oct 13 '13 at 06:03
  • @anujin In such case you can use `By.xpath(".//*")` - notice double slash instead of single one. Check this thread for more information: http://stackoverflow.com/questions/14052368/how-to-get-all-descendants-of-an-element-using-webdriver – JacekM Oct 13 '13 at 21:22
  • yes,`By.xpath(".//*")` is the one that worked for my purposes also. – kevin Dec 08 '16 at 21:45
9

Mayby it's too late for the owner of this question, but helpful for other.

List<WebElement> cells = row.findElements(By.xpath(".//*[local-name(.)='th' or local-name(.)='td']"));
plannapus
  • 18,529
  • 4
  • 72
  • 94
Chris
  • 91
  • 1
  • 1
3
// Grab the table
WebElement table = driver.findElement(By.id("searchResultsGrid"));

// Now get all the TR elements from the table
List<WebElement> allRows = table.findElements(By.tagName("tr"));
// And iterate over them, getting the cells
for (WebElement row : allRows) {
    List<WebElement> cells = row.findElements(By.tagName("td"));
    for (WebElement cell : cells) {
        System.out.println("content >>   " + cell.getText());
    }
}

using cell.getText() would simply work

Halvor Holsten Strand
  • 19,829
  • 17
  • 83
  • 99
3

You don't need to loop through elements. Instead, use a ByChained locator.

If you table looks like this:

<table>
  <tbody>
    <tr><th>Col1</th><th>Col2</th><th>Col3</th></tr>
    <tr><td>data</td><td>data</td><td>data</td></tr>
    <tr><td>data</td><td>data</td><td>data</td></tr>
    <tr><td>data</td><td>data</td><td>data</td></tr>
  </tbody>
</table>

The locate like this:

By tableBodyLocator = By.xpath(".//table/tbody");
By headerRowLocator = By.xpath(".//tr[position()=1]");
By dataRowsLocator = By.xpath(".//tr[not(position()=1)]");

By headerRowLocator = new ByChained(tableBodyLocator, headerRowLocator);
List<WebElement> weHeaders = driver.findElement(headerRowLocator)
       .findElements(By.xpath(".//th");
List<WebElement> allRowData = driver.findElements(tableBodyLocator, dataRowsLocator);

WebElement row1Data = allRowData.get(0);
WebElement row2Data = allRowData.get(1);

etc.
djangofan
  • 28,471
  • 61
  • 196
  • 289
0

yes it is working for c# with selenium...

IList<IWebElement> cells = row.findElements(By.xpath(".//*[local-name(.)='th' or local-name(.)='td']"));
amurra
  • 15,221
  • 4
  • 70
  • 87
kborkar
  • 17
  • 3
0
IWebElement table = driver.FindElement(By.Id("id"));
List<IWebElement> allRows = new List<IWebElement> (table.FindElements(By.TagName("tr")));

foreach (var Row in allRows)
{
    List<IWebElement> cells = new List<IWebElement>( Row.FindElements(By.TagName("td")));
    foreach (var cel in cells)
    {
        string test = cel.Text;
    }
}
Jose Ricardo Bustos M.
  • 8,016
  • 6
  • 40
  • 62
0

The below code you can not only get the rows and columns of the table but also you can get the order in which they are in the Browser,this is mainly handy if you have a nested structures in the TD column as in your case.

 public DataTable StoreHtmlTableToDataTable(IWebElement tblObj,bool isFirstRowHeader = true)
        {
            DataTable dataTbl = new DataTable();
            int rowIndex = 0;

            try
            {               
                //_tblDataCollection = new List<TableDataCollection>();

                var tblRows = ((IJavaScriptExecutor)DriverContext.Driver).ExecuteScript("return arguments[0].rows; ", tblObj);

                if (tblRows != null)
                {
                    //Iterate through each row of the table
                    foreach (IWebElement tr in (IEnumerable)tblRows)
                    {                        
                        int colIndx = 0;
                        DataRow dtRow =  dataTbl.NewRow();
                        // Iterate through each cell of the table row
                        var tblCols = ((IJavaScriptExecutor)DriverContext.Driver).ExecuteScript("return arguments[0].cells; ", tr);
                        foreach (IWebElement td in (IEnumerable)tblCols)
                        {
                            //add the header row of the table as  the datatable column hader row
                            if (rowIndex == 0)
                            {
                                dataTbl.Columns.Add("Col" + colIndx.ToString(), typeof(string));
                            }

                            dtRow["Col"+colIndx.ToString()] = td.Text;

                            //loop through any child or nested table structures if you want using the same approach for example links,radio buttons etc inside the cell

                            //Write Table to List : This part is not done yet                           
                            colIndx++;
                        }
                        dataTbl.Rows.Add(dtRow);
                        rowIndex++;
                    }

                }


            }
            catch (Exception)
            {
                throw;
            }

            //if first row is the header row then assign it as a header of the datatable
            if (isFirstRowHeader)
            {
                dataTbl = this.AssignDataTableHeader(dataTbl);
            }

            return dataTbl;
        }
0

TableDriver (https://github.com/jkindwall/TableDriver.Java) supports cells with both td and th tags. Using TableDriver with your example table would look something like this:

Table table = Table.createWithNoHeaders(driver.findElement(By.id(searchResultsGrid), 0);
List<TableRow> allRows = table.getRows();
for (TableRow row : allRows) {
    List<TableCell> cells = row.getCells();
    for (TableCell cell : cells) {
        // Access the cell's WebElement like this: cell.getElement()
    }
}
jkindwall
  • 3,816
  • 1
  • 17
  • 17