2012-07-10 11 views
6

私はEpplusを使用してExcelスプレッドシートをHTMLに変換しています。これまでのところ、1つのことを除いて非常にうまくいっています...統合されたセルにまたがっています。私はちょうど論理権を得るように見えない。私はそこでそれを投げ捨てて、コミュニティがそれをどのように扱うのか見てみようと思った。ここまでは私のコードです。Epplus Excelでマージされたセルを処理して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

私が尋ねる最初の質問は、それが細胞の結合を解除するためのワークシートを編集することができますかどうかです。試すだけの価値があります? –

+0

私はソースを編集することなくこれを解決したいと思っていますが、ソース文書を制御していません。 – BigBadOwl

+0

このトリックは、Epplusのcell.mergeがブール値を返すだけです。セルをチェックしてマージされているかどうかを確認すると、そのセルが前、後、下、または上にマージされているかどうかを知ることができないため、列スパンか列スパンかを判断できません。 – BigBadOwl

答えて

13

は、私の知る限り、これを言うことができるようにあなたが必要なものを正確にです。あなたが欠けていたものは、ワークシート上のMergedCellsプロパティで、シート内のすべてのマージされたセルがリストされていました。

私のコードは、行スパン、列スパン、およびその両方を同時に処理します。私は、行、列、および行/列の両方を含むスプレッドシートでいくつかのテストを行った。すべての場合において、彼らは完全に働いた。

コード

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

これは素晴らしい、魅力のように動作します。最終的にExcel文書をHTMLとして表示することはとても涼しいことです。すぐにGitHubに全コードを載せ、ここにリンクを投稿します。 Peterに感謝します。あなたのソリューションは50ポイント以上の価値があります。 – BigBadOwl

+1

あなたのcurrentCell.Valueの周囲にHtmlEncodeを配置してください。私はそれが立っているので、< or >記号がレンダリングにいくつかの問題を引き起こすと確信しています。 – Peter

+2

+1、マイナーな改善:常に 'Enumerable.Count()'の代わりに 'Enumerable.Any()'を使います。前者は要素が存在するかどうかをチェックし、後者はすべての要素を繰り返します。より良い: 'if(mCellsResult.Any()) ' –

関連する問題