Parsing HTML Tables

Applies to TestComplete 14.71, last modified on April 22, 2021

TestComplete provides scripting access to web page elements as well as to their attributes, methods and events. You can use this functionality to obtain data from tables displayed on the web page under test.

A table is an HTML TABLE element with special sub-elements for the table’s header, footer and body. These sub-elements contain rows and cells.

To retrieve data from a table, you can use the “native” properties of the DOM table object. Alternatively, you can use properties provided by TestComplete.

Using native properties

To retrieve data from a table, you can use the rows and cells properties of the table object (this is an object defined by the Document Object Model). The cells property belongs both to the table and to the row objects. The table’s property provides access to all cells of the table. The row’s property provides access to values displayed in the row’s cells.

The code below goes through the rows and cells of a table and posts the cell contents to the log. The sample routine works with the www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro web page displaying a sample table.

JavaScript, JScript

function SimpleParsing()
{
  var url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro";
  Browsers.Item(btIExplorer).Run(url);
  var page = Sys.Browser("*").Page("*");

  var table = page.WaitElement("#iframeResult").WaitElement("table");
  // You can also use the FindChild method
  // var table = page.FindChild("tagName", "table", 10);
  if (table.Exists)
  {
    // Goes through the rows and cells of the table
    for (var i = 0; i < table.rows.length; i++)
    {
      Log.AppendFolder("Row " + i);
      for (var j = 0; j < table.rows.item(i).cells.length; j++)
        Log.Message("Cell " + j + ": " + table.rows.item(i).cells.item(j).innerText);
      Log.PopLogFolder();
    }
  }
  else
    Log.Warning("The table was not found");

}

Python

def SimpleParsing():
  url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro"
  Browsers.Item[btIExplorer].Run(url)
  page = Sys.Browser("*").Page("*")

  table = page.WaitElement("#iframeResult").WaitElement("table")
  # You can also use the FindChild method
  # table = page.FindChild("tagName", "table", 10)
  if table.Exists:
    # Goes through the rows and cells of the table
    for i in range (0, table.rows.length):
      Log.AppendFolder("Row " + IntToStr(i))
      for j in range (0, table.rows.item(i).cells.length):
        Log.Message("Cell " + IntToStr(j) + ": " + table.rows.item(i).cells.item(j).innerText)
      Log.PopLogFolder()
  else:
    Log.Warning("The table was not found")

VBScript

Sub SimpleParsing

Dim page, table

  url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro"
  Browsers.Item(btIExplorer).Run url
  Set page = Sys.Browser("*").Page("*")

  Set table = page.WaitElement("#iframeResult").WaitElement("table")
  ' You can also use the FindChild method
  ' Set table = page.FindChild("tagName", "table", 10)
  If table.Exists Then

    ' Goes through the rows and cells of the table
    For i = 0 To table.rows.length - 1

      Log.AppendFolder("Row " & i)
      For j = 0 To table.rows.item(i).cells.length - 1
        Log.Message("Cell " & j & ": " & table.rows.item(i).cells.item(j).innerText)
      Next
      Log.PopLogFolder
    Next

  Else
    Log.Warning("The table was not found")

  End If

End Sub

DelphiScript

procedure SimpleParsing();

var url, page, table, i, j;

begin
  url := 'https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro';
  Browsers.Item(btIExplorer).Run(url);
  page := Sys.Browser('*').Page('*');

  table := page.WaitElement('#iframeResult').WaitElement('table');
  // You can also use the FindChild method
  // table := page.FindChild('tagName', 'table', 10);
  if table.Exists then
  begin
    // Goes through the rows and cells of the table
    for i := 0 to table.rows.length - 1 do
    begin
      Log.AppendFolder('Row ' + aqConvert.VarToStr(i));
      for j := 0 to table.rows.item(i).cells.length - 1 do
        Log.Message('Cell ' + aqConvert.VarToStr(j) + ': ' + table.rows.item(i).cells.item(j).innerText);
      Log.PopLogFolder();
    end;
  end
  else
    Log.Warning('The table was not found');
end;

C++Script, C#Script

function SimpleParsing()
{
  var url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro";
  Browsers["Item"](btIExplorer)["Run"](url);
  var page = Sys["Browser"]("*")["Page"]("*");
  var table = page["WaitElement"]("#iframeResult")["WaitElement"]("table");
  // You can also use the FindChild method
  // var table = page["FindChild"]("tagName", "table", 10);
  if (table["Exists"])
  {
    // Goes through the rows and cells of the table
    for (var i = 0; i < table["rows"]["length"]; i++)
    {
      Log["AppendFolder"]("Row " + i);
      for (var j = 0; j < table["rows"]["item"](i)["cells"]["length"]; j++)
        Log["Message"]("Cell " + j + ": " + table["rows"]["item"](i)["cells"]["item"](j)["innerText"]);
      Log["PopLogFolder"]();
    }
  }
  else
  Log["Warning"]("The table was not found");

}

Note that the rows property of the table object provides access to all rows of the table, including the rows displayed in the table’s header and footer. To only process cells of the table body, you obtain the objects corresponding to the TBODY elements (note that a table can contain several TBODY elements) and then go through the rows and cells of each TBODY.

The following code demonstrates how you can do this.

JavaScript, JScript

function Main()
{

  var url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro";
  Browsers.Item(btIExplorer).Run(url);
  var page = Sys.Browser("*").Page("*");

  var table = page.WaitElement("#iframeResult").WaitElement("table");
  // You can also use the FindChild method
  // var table = page.FindChild("tagName", "table", 10);
  if (table.Exists)
    // Parses the table
    ParseTable(table);
  else
    Log.Warning("The table is not found.");

}

function ParseTable(ATable)
{

  Log.AppendFolder("Table");

  // Parses the TBODY elements
  for (var i = 0; i < ATable.tBodies.length; i++)
  {
    Log.AppendFolder("TBody " + i);
    ParseTableBody(ATable.tBodies.item(i));
    Log.PopLogFolder();
  }

  Log.PopLogFolder();
}

// Parses TBODY
function ParseTableBody(ABody)
{
  // Goes through rows
  for (var i = 0; i < ABody.rows.length; i++)
  {
    // Obtains a row
    var row = ABody.rows.item(i);
    Log.AppendFolder("Row " + i);
    // Goes through cells
    for (var j = 0; j < row.cells.length; j++)
    {
      // Obtains a cell
      var cell = row.cells.item(j);
      // Posts the cell's text to the log
      Log.Message("Cell " + j + ": " + cell.innerText);
    }
    Log.PopLogFolder();
  }

}

Python

def Main():

  url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro"
  Browsers.Item[btIExplorer].Run(url)
  page = Sys.Browser("*").Page("*")

  table = page.WaitElement("#iframeResult").WaitElement("table")
  # You can also use the FindChild method
  # table = page.FindChild("tagName", "table", 10)
  if (table.Exists):
    # Parses the table
    ParseTable(table)
  else:
    Log.Warning("The table is not found.")

def ParseTable(ATable):

  Log.AppendFolder("Table");

  # Parses the TBODY elements
  for i in range (0, ATable.tBodies.length):
    Log.AppendFolder("TBody " + IntToStr(i))
    ParseTableBody(ATable.tBodies.item(i))
    Log.PopLogFolder()

  Log.PopLogFolder()

# Parses TBODY
def ParseTableBody(ABody):
  # Goes through rows
  for i in range (0, ABody.rows.length):
    # Obtains a row
    row = ABody.rows.item(i)
    Log.AppendFolder("Row " + IntToStr(i))
    # Goes through cells
    for j in range (0, row.cells.length):
      # Obtains a cell
      cell = row.cells.item(j)
      # Posts the cell's text to the log
      Log.Message("Cell " + IntToStr(j) + ": " + cell.innerText)
    Log.PopLogFolder()

VBScript

Sub Main

  Dim page, table

  url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro"
  Browsers.Item(btIExplorer).Run url
  Set page = Sys.Browser("*").Page("*")

  Set table = page.WaitElement("#iframeResult").WaitElement("table")
  ' You can also use the FindChild method
  ' Set table = page.FindChild("tagName", "table", 10)
  If table.Exists Then
    ' Parses the table
    ParseTable(table)
  Else
    Log.Warning("The table was not found.")
  End If
End Sub

Sub ParseTable(ATable)
  Dim i
  Log.AppendFolder("Table")
  ' Parses the TBODY elements
  For i = 0 To ATable.tBodies.length - 1
    Log.AppendFolder("TBody " & i)
    ParseTableBody(ATable.tBodies.item(i))
    Log.PopLogFolder
  Next

  Log.PopLogFolder
End Sub

' Parses TBODY
Sub ParseTableBody(ABody)

  Dim i, j, row, cell

  ' Goes through rows
  For i = 0 To ABody.rows.length - 1
    ' Obtains a row
    Set row = ABody.rows.item(i)
    Log.AppendFolder("Row " & i)
    ' Goes through cells
    For j = 0 To row.cells.length - 1
      ' Obtains a cell
      Set cell = row.cells.item(j)
      ' Posts the cell's text to the log
      Log.Message("Cell " & j & ": " & cell.innerText)
    Next
    Log.PopLogFolder()
  Next

End Sub

DelphiScript

// Forward declarations
procedure ParseTable(ATable); forward;
procedure ParseTableBody(ABody); forward;

procedure Main();
var url, page, table;
begin

  url := 'https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro';
  Browsers.Item(btIExplorer).Run(url);
  page := Sys.Browser('*').Page('*');

  table := page.WaitElement('#iframeResult').WaitElement('table');
  // You can also use the FindChild method
  // table := page.FindChild('tagName', 'table', 10);
  if table.Exists then
    // Parses the table
    ParseTable(table)
  else
    Log.Warning('The table was not found.');
end;

procedure ParseTable(ATable);
var i;
begin

  Log.AppendFolder('Table');
  // Parses the TBODY elements
  for i := 0 to ATable.tBodies.length - 1 do
  begin
    Log.AppendFolder('TBody ' + aqConvert.VarToStr(i));
    ParseTableBody(ATable.tBodies.item[i]);
    Log.PopLogFolder;
  end;
  Log.PopLogFolder;

end;

// Parses TBODY
procedure ParseTableBody(ABody);
var i, j, row, cell;
begin

  // Goes through rows
  for i := 0 to ABody.rows.length - 1 do
  begin
    // Obtains a row
    row := ABody.rows.item[i];
    Log.AppendFolder('Row ' + aqConvert.VarToStr(i));
    // Goes through cells
    for j := 0 to row.cells.length - 1 do
    begin
      // Obtains a cell
      cell := row.cells.item[j];
      // Posts the cell's text to the log
      Log.Message('Cell ' + aqConvert.VarToStr(j) + ': ' + cell.innerText);
    end;
    Log.PopLogFolder;
  end;
end;

C++Script, C#Script

function Main()
{

  var url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro";
  Browsers["Item"](btIExplorer)["Run"](url);
  var page = Sys["Browser"]("*")["Page"]("*");
  var table = page["WaitElement"]("#iframeResult")["WaitElement"]("table");
  // You can also use the FindChild method
  // var table = page["FindChild"]("tagName", "table", 10);
  if (table["Exists"])
    // Parses the table
    ParseTable(table);
  else
    Log["Warning"]("The table was not found.");

}

function ParseTable(ATable)
{

  Log["AppendFolder"]("Table");

  // Parses the TBODY elements
  for (var i = 0; i < ATable["tBodies"]["length"]; i++)
  {
    Log["AppendFolder"]("TBody " + i);
    ParseTableBody(ATable["tBodies"]["item"](i));
    Log["PopLogFolder"]();
  }

  Log["PopLogFolder"]();
}

// Parses TBODY
function ParseTableBody(ABody)
{
  // Goes through rows
  for (var i = 0; i < ABody["rows"]["length"]; i++)
  {
    // Obtains a row
    var row = ABody["rows"]["item"](i);
    Log["AppendFolder"]("Row " + i);
    // Goes through cells
    for (var j = 0; j < row["cells"]["length"]; j++)
    {
      // Obtains a cell
      var cell = row["cells"]["item"](j);
      // Posts the cell's text to the log
      Log["Message"]("Cell " + j + ": " + cell["innerText"]);
    }
    Log["PopLogFolder"]();
  }

}

Using properties provided by TestComplete

When exposing internals of a tested web application, TestComplete builds a hierarchy of the tested application’s objects. This hierarchy reflects the actual hierarchy of objects on the HTML page under test in the web object tree. A table object has child Cell objects that correspond to the table cells. Cells are addressed using their zero-based row and column indexes. For instance, the Cell(2, 1) notation corresponds to the second cell in the third row. Besides that, TestComplete extends the functionality of the DOM table object with the RowCount and ColumnCount(RowIndex) properties. The RowCount property returns the number of table rows, and the ColumnCount property lets you get the number of cells in the row with the RowIndex index (in general, table rows can contain a different number of cells). You can use these properties for iterating through the table cells.

Below is an example that processes a table using the described approach.

JavaScript, JScript

function Test()
  {
  switch (Options.Web.TreeModel)
  {
    case "DOM":
    case "Tag":
      Log.Warning("This example requires the Tree model. Setting the model to Tree.");
      Options.Web.TreeModel = "Tree";
      break;
  }

  var url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro";
  Browsers.Item(btIExplorer).Run(url);
  var page = Sys.Browser("*").Page("*");

  var table = page.FindElement("#iframeResult").FindElement("table");
  // You can also use the FindChild method
  // var table = page.FindChild("tagName", "table", 10);
  // Parses the table
  ParseTreeTable(table);
  }

function ParseTreeTable(ATable)
{
  Log.AppendFolder("Table");
  for (var i = 0; i < ATable.RowCount; i++)

  {
    Log.AppendFolder("Row " + i);

    // Goes through cells
    for (var j = 0; j < ATable.ColumnCount(i); j++)

    {
      // Obtains a cell
      var cell = ATable.Cell(i, j);
      // Posts the cell's text to the log
      Log.Message("Cell " + j + ": " + cell.innerText);
    }

    Log.PopLogFolder();
  }

  Log.PopLogFolder();

}

Python

def Test():
  if (Options.Web.TreeModel == "DOM" or
      Options.Web.TreeModel == "Tag"):
    Log.Warning("This example requires the Tree model. Setting the model to Tree.")
    Options.Web.TreeModel = "Tree"

  url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro"
  Browsers.Item[btIExplorer].Run(url)
  page = Sys.Browser("*").Page("*")

  table = page.FindElement("#iframeResult").FindElement("table")
  # You can also use the FindChild method
  # table = page.FindChild("tagName", "table", 10)

  # Parses the table
  ParseTreeTable(table)

def ParseTreeTable(ATable):
  Log.AppendFolder("Table")
  for i in range (0, ATable.RowCount):

    Log.AppendFolder("Row " + IntToStr(i))

    # Goes through cells
    for j in range (0, ATable.ColumnCount[i]):

      # Obtains a cell
      cell = ATable.Cell(i, j)
      # Posts the cell's text to the log
      Log.Message("Cell " + IntToStr(j) + ": " + cell.innerText)

    Log.PopLogFolder()

  Log.PopLogFolder()

VBScript

Sub Test()

  Dim page, table

  Select Case Options.Web.TreeModel
    Case "DOM"
      Log.Warning("This example requires the Tree model. Setting the model to Tree.")
      Options.Web.TreeModel = "Tree"
    Case "Tag"
      Log.Warning("This example requires the Tree model. Setting the model to Tree.")
      Options.Web.TreeModel = "Tree"
  End Select

  url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro"
  Browsers.Item(btIExplorer).Run url
  Set page = Sys.Browser("*").Page("*")

  Set table = page.FindElement("#iframeResult").FindElement("table")
  ' You can also use the FindChild method
  ' Set table = page.FindChild("tagName", "table", 10)
  ' Parses the table
  ParseTreeTable(table)
  End Sub

  Sub ParseTreeTable(ATable)

  Dim i, j
  Log.AppendFolder("Table")
  For i = 0 To ATable.RowCount - 1
    Log.AppendFolder("Row " & i)
    ' Goes through cells
    For j = 0 To ATable.ColumnCount(i) - 1

      ' Obtains a cell
      Set cell = ATable.Cell(i, j)
      ' Posts the cell's text to the log
      Log.Message("Cell " & j & ": " & cell.innerText)
    Next

    Log.PopLogFolder()
  Next

  Log.PopLogFolder()

End Sub

DelphiScript

// Forward declaration
procedure ParseTreeTable(ATable); forward;

procedure Test();
var url, browser, page, table;
begin

  case Options.Web.TreeModel of
  'DOM':
    begin
      Log.Warning('This example requires the Tree model. Setting the model to Tree.');
      Options.Web.TreeModel := 'Tree';
    end;
  'Tag':
    begin
      Log.Warning('This example requires the Tree model. Setting the model to Tree.');
      Options.Web.TreeModel := 'Tree';
    end;
  end;

  url := 'https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro';
  Browsers.Item(btIExplorer).Run(url);
  page := Sys.Browser('*').Page('*');

  table := page.FindElement('#iframeResult').FindElement('table');
  // You can also use the FindChild method
  // table := page.FindChild('tagName', 'table', 10);
  // Parses the table
  ParseTreeTable(table);
end;

procedure ParseTreeTable(ATable);
var i, j, cell;
begin

  Log.AppendFolder('Table');
  for i := 0 to ATable.RowCount - 1 do
  begin
    Log.AppendFolder('Row ' + aqConvert.VarToStr(i));

    // Goes through cells
    for j := 0 to ATable.ColumnCount(i)-1 do
    begin
      // Obtains a cell
      cell := ATable.Cell(i, j);
      // Posts the cell's text to the log
      Log.Message('Cell ' + aqConvert.VarToStr(j) + ': ' + cell.innerText);
    end;

    Log.PopLogFolder;
  end;

  Log.PopLogFolder;
end;

C++Script, C#Script

function Test()
  {
  switch (Options.Web.TreeModel)
  {
    case "DOM":
    case "Tag":
      Log["Warning"]("This example requires the Tree model. Setting the model to Tree.");
      Options["Web"]["TreeModel"] = "Tree";
      break;
  }

  var url = "https://www.w3schools.com/html/tryit.asp?filename=tryhtml_table_intro";
  Browsers["Item"](btIExplorer)["Run"](url);
  var page = Sys["Browser"]("*")["Page"]("*");
  var table = page["FindElement"]("#iframeResult")["FindElement"]("table");
  // You can also use the FindChild method
  // var table = page["FindChild"]("tagName", "table", 10);
  // Parses the table
  ParseTreeTable(table);
  }

function ParseTreeTable(ATable)
{
  Log["AppendFolder"]("Table");
  for (var i = 0; i < ATable["RowCount"]; i++)

  {
    Log["AppendFolder"]("Row " + i);

    // Goes through cells
    for (var j = 0; j < ATable["ColumnCount"](i); j++)

    {
      // Obtains a cell
      var cell = ATable["Cell"](i, j);
      // Posts the cell's text to the log
      Log["Message"]("Cell " + j + ": " + cell["innerText"]);
    }

    Log["PopLogFolder"]();
  }

  Log["PopLogFolder"]();

}

Note, however, that the table’s child Cell objects provide access to all table cells, including those displayed in the table header and footer. If you only need to process the table body cells, use the approach described in the previous section.

You can call the described script routines from keyword tests. To do this, use the Run Script Routine operation. Prepare the script code and then add the operation to your keyword test. TestComplete will display the Select Test dialog where you will be able to choose the desired routine.

See Also

Default Web Testing
Web Testing - Examples

Highlight search results