Sometimes, we have situations where we get data as HTML data and we have to convert it to DataTable. From DataTable, we can export it to xlsx or use it according to our need.

The problem I faced with HTML data, was that I had to export a report in xlsx format and I had only HTML data. The HTML data was exporting into xlsx but with a format message, while opening the Excel. That means, it was writing the HTML to the Excel sheet as it appeared. But for the Excel sheet, we need columns to be written properly into each cell. xlsx doesn't support direct HTML conversion to xlsx cells.
To export HTML data to xlsx, I had to convert the HTML data to DataTable from where I can export the data easily and there will be no format message while opening the Excel. Below is the code to convert the HTML to DataTable.
  1. public static DataTable ConvertHTMLTablesToDataTable(string HTML)
  2. {
  3. DataTable dt = null;
  4. DataRow dr = null;
  5. DataColumn dc = null;
  6. string TableExpression = "<table[^>]*>(.*?)</table>";
  7. string HeaderExpression = "<th[^>]*>(.*?)</th>";
  8. string RowExpression = "<tr[^>]*>(.*?)</tr>";
  9. string ColumnExpression = "<td[^>]*>(.*?)</td>";
  10. bool HeadersExist = false;
  11. int iCurrentColumn = 0;
  12. int iCurrentRow = 0;
  13. // Get a match for all the tables in the HTML
  14. MatchCollection Tables = Regex.Matches(HTML, TableExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
  15. // Loop through each table element
  16. foreach (Match Table in Tables)
  17. {
  18. // Reset the current row counter and the header flag
  19. iCurrentRow = 0;
  20. HeadersExist = false;
  21. // Add a new table to the DataSet
  22. dt = new DataTable();
  23. // Create the relevant amount of columns for this table (use the headers if they exist, otherwise use default names)
  24. if (Table.Value.Contains("<th"))
  25. {
  26. // Set the HeadersExist flag
  27. HeadersExist = true;
  28. // Get a match for all the rows in the table
  29. MatchCollection Headers = Regex.Matches(Table.Value, HeaderExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
  30. // Loop through each header element
  31. foreach (Match Header in Headers)
  32. {
  33. //dt.Columns.Add(Header.Groups(1).ToString);
  34. dt.Columns.Add(Header.Groups[1].ToString());
  35. }
  36. }
  37. else
  38. {
  39. for (int iColumns = 1; iColumns <= Regex.Matches(Regex.Matches(Regex.Matches(Table.Value, TableExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase)[0].ToString(), RowExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase)[0].ToString(), ColumnExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase).Count; iColumns++)
  40. {
  41. dt.Columns.Add("Column " + iColumns);
  42. }
  43. }
  44. // Get a match for all the rows in the table
  45. MatchCollection Rows = Regex.Matches(Table.Value, RowExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
  46. // Loop through each row element
  47. foreach (Match Row in Rows)
  48. {
  49. // Only loop through the row if it isn't a header row
  50. if (!(iCurrentRow == 0 & HeadersExist == true))
  51. {
  52. // Create a new row and reset the current column counter
  53. dr = dt.NewRow();
  54. iCurrentColumn = 0;
  55. // Get a match for all the columns in the row
  56. MatchCollection Columns = Regex.Matches(Row.Value, ColumnExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
  57. // Loop through each column element
  58. foreach (Match Column in Columns)
  59. {
  60. DataColumnCollection columns = dt.Columns;
  61. if (!columns.Contains("Column " + iCurrentColumn))
  62. {
  63. //Add Columns
  64. dt.Columns.Add("Column " + iCurrentColumn);
  65. }
  66. // Add the value to the DataRow
  67. dr[iCurrentColumn] = Column.Groups[1].ToString();
  68. // Increase the current column
  69. iCurrentColumn += 1;
  70. }
  71. // Add the DataRow to the DataTable
  72. dt.Rows.Add(dr);
  73. }
  74. // Increase the current row counter
  75. iCurrentRow += 1;
  76. }
  77. }
  78. return (dt);
  79. }
This line gets all the Table matches as defined in TableExpression variable.
  1. MatchCollection Tables = Regex.Matches(HTML, TableExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
This line gets the total number of columns using ColumnExpressions as <td>. It created each <td> as a column.
  1. MatchCollection Columns = Regex.Matches(Row.Value, ColumnExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
This line gets the header using HeaderExpression as <th>. It created each <th> as a Header.
  1. MatchCollection Headers = Regex.Matches(Table.Value, HeaderExpression, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
Use this code to convert HTML to DataTable. If you have found any problem, please comment below.