title: Handle merged cells in Epplus Excel conversion to HTML
body: <p>I'm using Epplus to render an Excel spreadsheet into HTML. So far it's going very, very well, except for one thing... spanning merged cells. I just can't seem to get the logic right. I thought I would throw it out there to see how the community would deal with it. Here is my code so far.</p>
  
  <pre><code>public String ParseExcelStamps(String FileName)
  {
      FileInfo theFile = new FileInfo(FileName);
      String html = "";
      using (ExcelPackage xlPackage = new ExcelPackage(theFile))
      {
          var workbook = xlPackage.Workbook;
          if (workbook != null)
          {
              for (int j = 1; j &lt;= workbook.Worksheets.Count; j++)
              {
                  Tab tab = new Tab();
                  html+= "&lt;table style='border-collapse: collapse;font-family:arial;'&gt;&lt;tbody&gt;";
                  var worksheet = workbook.Worksheets[j];
                  tab.Title = worksheet.Name;
                  if (worksheet.Dimension == null) { continue; }
                  int rowCount = 0;
                  int maxColumnNumber = worksheet.Dimension.End.Column;
                  var convertedRecords = new List&lt;List&lt;string&gt;&gt;(worksheet.Dimension.End.Row);
                  var excelRows = worksheet.Cells.GroupBy(c =&gt; c.Start.Row).ToList();
                  excelRows.ForEach(r =&gt;
                  {
                      rowCount++;
                      html += String.Format("&lt;tr&gt;");
                      var currentRecord = new List&lt;string&gt;(maxColumnNumber);
                      var cells = r.OrderBy(cell =&gt; cell.Start.Column).ToList();
                      Double rowHeight = worksheet.Row(rowCount).Height;
                      for (int i = 1; i &lt;= maxColumnNumber; i++)
                      {
                          var currentCell = cells.Where(c =&gt; c.Start.Column == i).FirstOrDefault();
  
                          //look aheads for colspan and rowspan
                          ExcelRangeBase previousCellAbove = null;
                          ExcelRangeBase previousCell = null;
                          ExcelRangeBase nextCell = null;
                          ExcelRangeBase nextCellBelow = null;
                          try { previousCellAbove = worksheet.Cells[rowCount-1, i]; }catch (Exception) { }
                          try { previousCell = worksheet.Cells[rowCount, (i - 1)]; }catch (Exception) { }
                          try { nextCell = worksheet.Cells[rowCount, (i + 1)]; }catch (Exception) { }
                          try { nextCellBelow = worksheet.Cells[rowCount+1, i]; }catch (Exception) { }
  
                          if ((previousCell != null) &amp;&amp; (previousCell.Merge) &amp;&amp; (currentCell != null) &amp;&amp; (currentCell.Merge)){continue;}
                          if ((previousCellAbove != null) &amp;&amp; (previousCellAbove.Merge) &amp;&amp; (currentCell != null)) {continue; }
  
                          if (currentCell == null)
                          {
                              html += String.Format("&lt;td&gt;{0}&lt;/td&gt;", String.Empty);
                          }
                          else
                          {
                              int colSpan = 1;
                              int rowSpan = 1;
                              if ((nextCell != null) &amp;&amp; (nextCell.Merge) &amp;&amp; (currentCell.Merge)) {
                                  colSpan = 2;
                                 // Console.WriteLine(String.Format("{0} - {1}", currentCell.Address, nextCell.Address));
                              }
  
                              if ((nextCellBelow != null) &amp;&amp; (nextCellBelow.Merge) &amp;&amp; (currentCell.Merge)) {
                                  Console.WriteLine(String.Format("{0} - {1}", currentCell.Address, nextCellBelow.Address));
                              }
  
                              html += String.Format("&lt;td colspan={0} rowspan={1}&gt;{2}&lt;/td&gt;", colSpan, rowSpan, currentCell.Value);
                          }
                      }
                      html += String.Format("&lt;/tr&gt;");
                  });
                  html += "&lt;/tbody&gt;&lt;/table&gt;";
              }//worksheet loop
          }
      }
      return html;
  }
  </code></pre>