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:
// 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
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.
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;
}
yes it is working for c# with selenium...
IList<IWebElement> cells = row.findElements(By.xpath(".//*[local-name(.)='th' or local-name(.)='td']"));
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("./*"));
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;
}
}