2012-07-10 27 views
6

Tôi đang sử dụng Epplus để hiển thị bảng tính Excel thành HTML. Cho đến nay nó sẽ rất, rất tốt, ngoại trừ một điều ... kéo dài các tế bào sáp nhập. Tôi dường như không thể hiểu được logic. Tôi nghĩ tôi sẽ ném nó ra đó để xem cộng đồng sẽ đối phó với nó như thế nào. Đây là mã của tôi cho đến nay.Xử lý các ô đã phối trong chuyển đổi Epplus Excel sang 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

Câu hỏi đầu tiên tôi sẽ hỏi là liệu nó có thể chỉnh sửa bảng tính hủy hợp nhất tế bào. Giá trị một thử? –

+0

Tôi thực sự muốn giải quyết điều này mà không cần phải chỉnh sửa nguồn, cộng với Im không kiểm soát các tài liệu nguồn. – BigBadOwl

+0

Bí quyết với điều này là cell.merge của Epplus chỉ trả về một Boolean. Khi bạn kiểm tra một ô để xem nếu nó được hợp nhất, bạn không thể biết nếu nó được hợp nhất với ô trước, sau, bên dưới hoặc trên và do đó không thể xác định xem đó là một colspan hay một hàng. – BigBadOwl

Trả lời

13

Theo tôi có thể nói đây chính xác là những gì bạn cần. Những gì bạn bị thiếu là thuộc tính MergedCells trên trang tính liệt kê tất cả các ô được hợp nhất trong trang tính.

Mã của tôi xử lý hàng kéo dài, nhịp cột và cả hai cùng một lúc. Tôi đã làm một số thử nghiệm với một bảng tính bao gồm cả hàng, cột và hàng/cột trải rộng. Trong mọi trường hợp, họ làm việc hoàn hảo.

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

Điều này thật tuyệt vời, hoạt động như một sự quyến rũ. Thật tuyệt vời khi cuối cùng có thể hiển thị tài liệu Excel dưới dạng HTML. Tôi sẽ sớm đưa mã đầy đủ vào GitHub và đăng liên kết ở đây. Cảm ơn Peter, giải pháp của bạn đáng giá 50 điểm trở lên. – BigBadOwl

+1

Đảm bảo đặt HtmlEncode quanh currentCell.Value của bạn. Tôi khá chắc chắn rằng vì nó đứng một dấu hiệu < or > sẽ gây ra một số vấn đề với rendering. – Peter

+2

+1, một cải tiến nhỏ: luôn luôn sử dụng 'Enumerable.Any()' thay vì 'Enumerable.Count()'. Trước đây chỉ kiểm tra nếu có bất kỳ phần tử nào tồn tại, phần tử thứ hai lặp lại tất cả các phần tử. Tốt hơn: 'if (mCellsResult.Any())' –