2012-07-10 13 views
6

Ich verwende Epplus, um eine Excel-Tabelle in HTML zu rendern. Bis jetzt läuft es sehr, sehr gut, bis auf eine Sache ... übergreifende Zellen. Ich kann die Logik nicht richtig verstehen. Ich dachte, ich würde es rauswerfen, um zu sehen, wie die Gemeinschaft damit umgehen würde. Hier ist mein Code soweit.Behandeln Sie fusionierte Zellen in Epplus Excel-Konvertierung in HTML

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 <= workbook.Worksheets.Count; j++) 
      { 
       Tab tab = new Tab(); 
       html+= "<table style='border-collapse: collapse;font-family:arial;'><tbody>"; 
       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<List<string>>(worksheet.Dimension.End.Row); 
       var excelRows = worksheet.Cells.GroupBy(c => c.Start.Row).ToList(); 
       excelRows.ForEach(r => 
       { 
        rowCount++; 
        html += String.Format("<tr>"); 
        var currentRecord = new List<string>(maxColumnNumber); 
        var cells = r.OrderBy(cell => cell.Start.Column).ToList(); 
        Double rowHeight = worksheet.Row(rowCount).Height; 
        for (int i = 1; i <= maxColumnNumber; i++) 
        { 
         var currentCell = cells.Where(c => 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) && (previousCell.Merge) && (currentCell != null) && (currentCell.Merge)){continue;} 
         if ((previousCellAbove != null) && (previousCellAbove.Merge) && (currentCell != null)) {continue; } 

         if (currentCell == null) 
         { 
          html += String.Format("<td>{0}</td>", String.Empty); 
         } 
         else 
         { 
          int colSpan = 1; 
          int rowSpan = 1; 
          if ((nextCell != null) && (nextCell.Merge) && (currentCell.Merge)) { 
           colSpan = 2; 
           // Console.WriteLine(String.Format("{0} - {1}", currentCell.Address, nextCell.Address)); 
          } 

          if ((nextCellBelow != null) && (nextCellBelow.Merge) && (currentCell.Merge)) { 
           Console.WriteLine(String.Format("{0} - {1}", currentCell.Address, nextCellBelow.Address)); 
          } 

          html += String.Format("<td colspan={0} rowspan={1}>{2}</td>", colSpan, rowSpan, currentCell.Value); 
         } 
        } 
        html += String.Format("</tr>"); 
       }); 
       html += "</tbody></table>"; 
      }//worksheet loop 
     } 
    } 
    return html; 
} 
+0

Die erste Frage, die ich fragen würde, ob es möglich ist, um das Arbeitsblatt zu bearbeiten Zellen unmerge. Einen Versuch wert? –

+0

Ich möchte das wirklich lösen, ohne die Quelle bearbeiten zu müssen, und ich habe keine Kontrolle über die Quelldokumente. – BigBadOwl

+0

Der Trick dabei ist, dass Epplus cell.merge nur einen booleschen Wert zurückgibt. Wenn Sie eine Zelle überprüfen, um zu sehen, ob sie verschmolzen ist, können Sie nicht feststellen, ob sie mit der Zelle vor, nach, unterhalb oder oberhalb zusammengeführt wurde. Daher können Sie nicht feststellen, ob es sich um einen Spalten- oder Zeilenbereich handelt. – BigBadOwl

Antwort

13

Soweit ich sagen kann, ist dies genau das, was Sie brauchen. Was Sie vermissten, war die MergedCells -Eigenschaft auf dem Arbeitsblatt, die alle verbundenen Zellen in dem Blatt auflistet.

Mein Code behandelt Zeilenspannen, Spaltenspannen und beides gleichzeitig. Ich habe einige Tests mit einer Tabelle durchgeführt, die sowohl Zeilen- als auch Spalten- und Zeilen/Spalten-Spanning enthielt. In allen Fällen haben sie perfekt funktioniert.

-Code

int colSpan = 1; 
int rowSpan = 1; 

//check if this is the start of a merged cell 
ExcelAddress cellAddress = new ExcelAddress(currentCell.Address); 

var mCellsResult = (from c in worksheet.MergedCells 
       let addr = new ExcelAddress(c) 
        where cellAddress.Start.Row >= addr.Start.Row && 
        cellAddress.End.Row <= addr.End.Row && 
        cellAddress.Start.Column >= addr.Start.Column && 
        cellAddress.End.Column <= addr.End.Column 
       select addr); 

if (mCellsResult.Count() >0) 
{ 
    var mCells = mCellsResult.First(); 

    //if the cell and the merged cell do not share a common start address then skip this cell as it's already been covered by a previous item 
    if (mCells.Start.Address != cellAddress.Start.Address) 
     continue; 

    if(mCells.Start.Column != mCells.End.Column) { 
     colSpan += mCells.End.Column - mCells.Start.Column; 
    } 

    if (mCells.Start.Row != mCells.End.Row) 
    { 
     rowSpan += mCells.End.Row - mCells.Start.Row; 
    } 
} 

//load up data 
html += String.Format("<td colspan={0} rowspan={1}>{2}</td>", colSpan, rowSpan, currentCell.Value); 
+0

Das ist brilliant, wirkt wie ein Zauber. Es ist so cool, endlich ein Excel-Dokument als HTML anzeigen zu können. Ich werde den vollständigen Code bald auf GitHub veröffentlichen und den Link hier posten. Danke Peter, deine Lösung ist 50 Punkte und mehr wert. – BigBadOwl

+1

Stellen Sie sicher, dass Sie einen HtmlEncode um Ihren currentCell.Value legen. Ich bin ziemlich sicher, dass, wie es ein < or > Zeichen steht, einige Probleme mit dem Rendering verursachen würde. – Peter

+2

+1, eine kleine Verbesserung: Verwenden Sie immer 'Enumerable.Any()' anstelle von 'Enumerable.Count()'. Ersteres prüft nur, ob ein Element existiert, letzteres iteriert alle Elemente. Besser: 'if (mCellsResult.Any())' –

Verwandte Themen