Javascript get table cell 2D array considering colspan and rowspan

Viewed 1932

I have a table with colspans and rowspans like this 5x3 table:

<table id="test">
  <tr>
    <td colspan="2">1</td><td>2</td><td rowspan="2">3</td><td>4</td>
  </tr>
  <tr>
    <td>5</td><td colspan="2">6</td><td>7</td>
  </tr>
  <tr>
    <td>8</td><td>9</td><td>10</td><td>11</td><td>12</td>
  </tr>
</table>

example

I want to create 2D array in Javascript which contains cell DOM elements at given coordinates.
For given example it is following (for simplicity, numbers mean DOM cell elements with corresponding content):

[[1, 1, 2, 3, 4], [5, 6, 6, 3, 7], [8, 9, 10, 11, 12]]

You see, it is like Javascript property table.rows, but cells with colspan/rowspan appear many times. If only colspan is allowed it is not difficult to create such array - just loop over table.rows and push to array cells as many times as colspan is. However, when rowspan is also allowed, this becomes tricky.

Here is my attempt:

  var tableEl = document.getElementById('test');
  var cells2D = [];
  var rows = tableEl.rows;
  var x = 0, y = 0;
  for (var r = 0; r < rows.length; ++r) {
    var cells = rows[r].cells;
    x = 0;
    for (var c = 0; c < cells.length; ++c) {
      var cell = cells[c];
      var colSpan = x + (cell.colSpan || 1);
      var rowSpan = y + (cell.rowSpan || 1);
      for (var x2 = x; x2 < colSpan; ++x2) {
        for (var y2 = y; y2 < rowSpan; ++y2) {
          if (!cells2D[y2]) cells2D[y2] = [];
          cells2D[y2][x2] = cell;
        }
        ++x;
      }
    }
    ++y;
  }

It doesn't works on example, but if I remove last column then it works.

2 Answers

I needed to do the same, but in C# (using AngleSharp library), so I ported Somnium's answer:

static IHtmlTableCellElement[,] GetTableEffectiveCells(IHtmlTableElement table)
{
    var rowCount = table.Rows.Length;
    var columnCount = table.Rows.Max(row => row.Cells.Length);
    var cells = new IHtmlTableCellElement?[rowCount, columnCount];

    for (var r = 0; r < rowCount; r++)
    {
        var x = 0;

        foreach (var cell in table.Rows[r].Cells)
        {
            while (cells[r, x] != null) x++;

            var x3 = x + cell.ColumnSpan;
            var y3 = r + cell.RowSpan;

            for (var y2 = r; y2 < y3; y2++)
            for (var x2 = x; x2 < x3; x2++)
                cells[y2, x2] = cell;

            x = x3;
        }
    }

    return cells!;
}
Related