2015-10-22 112 views
3

我正在構建一個工具來自動創建包含表和關聯的數據透視表的Excel工作簿。表格結構在一張紙上,稍後使用另一個工具從數據庫中提取數據。數據透視表位於第二張紙上,使用上一張紙的表作爲來源。將表格而非範圍定義爲數據透視表'cacheSource'

我正在使用EPPlus來幫助構建工具,但遇到了指定cacheSource的問題。我使用以下內容來創建的範圍和數據透視表:

var dataRange = dataWorksheet.Cells[dataWorksheet.Dimension.Address.ToString()]; 

var pivotTable = pivotWorksheet.PivotTables.Add(pivotWorksheet.Cells["B3"], dataRange, name); 

這設置cacheSource到:

<x:cacheSource type="worksheet" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> 
<x:worksheetSource ref="A1:X2" sheet="dataWorksheet" /> 

或Excel內,數據源被設置爲:

dataWorksheet!$A$1:$X$2 

如果表的大小從不改變,但這種工作正常,但由於行數是動態的,我正在查找何時刷新數據,數據只能從指定的初始範圍讀取。

我所想要做的就是給cacheSource編程設置爲:

<x:cacheSource type="worksheet" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> 
    <x:worksheetSource name="dataWorksheet" /> 
</x:cacheSource> 

或Excel中,設置數據源:

dataWorksheet 

我相信這是可能做到這通過直接訪問XML(任何指針在這將是最受歡迎的),但有沒有辦法使用EPPlus做到這一點?

+0

如果源數據是一個表(在Excel的INSERT> Tables - Table)PT緩存可以由類似'Table1'而不是範圍來驅動,所以在刷新時,PT會自動獲取插入到表中的所有新條目。 – pnuts

+1

感謝您的評論;這是我正在嘗試設置的。 EPPlus似乎沒有將源數據添加爲表格的方法;它似乎只會接受一個靜態範圍。 – BadgersArise

回答

1

它可以做到,但它不是世界上最漂亮的東西。您可以從創建的EPPlus數據透視表對象中提取緩存def xml並對其進行編輯,但當您調用package.save()(或GetAsByteArray())時會因保存邏輯分析保存中的xml以生成最終文件而造成嚴重後果。正如你所說,這是EPPlus無法處理表格作爲源的結果。

因此,您的替代方案是正常地將文件與EPPlus一起保存,然後使用.net ZipArchive操作xlsx的內容,該文件是一個重命名的zip文件。訣竅是你不能在zip中按順序操作文件,否則Excel會在打開文件時發出抱怨。由於您無法插入條目(只能添加到最後),因此您必須重新創建該條目。這裏是一個ZipArchive擴展方法,讓你更新緩存來源:

public static bool SetCacheSourceToTable(this ZipArchive xlsxZip, FileInfo destinationFileInfo, string tablename, int cacheSourceNumber = 1) 
{ 
    var cacheFound = false; 
    var cacheName = String.Format("pivotCacheDefinition{0}.xml", cacheSourceNumber); 

    using (var copiedzip = new ZipArchive(destinationFileInfo.Open(FileMode.Create, FileAccess.ReadWrite), ZipArchiveMode.Update)) 
    { 
     //Go though each file in the zip one by one and copy over to the new file - entries need to be in order 
     xlsxZip.Entries.ToList().ForEach(entry => 
     { 
      var newentry = copiedzip.CreateEntry(entry.FullName); 
      var newstream = newentry.Open(); 
      var orgstream = entry.Open(); 

      //Copy all other files except the cache def we are after 
      if (entry.Name != cacheName) 
      { 
       orgstream.CopyTo(newstream); 
      } 
      else 
      { 
       cacheFound = true; 

       //Load the xml document to manipulate 
       var xdoc = new XmlDocument(); 
       xdoc.Load(orgstream); 

       //Get reference to the worksheet xml for proper namespace 
       var nsm = new XmlNamespaceManager(xdoc.NameTable); 
       nsm.AddNamespace("default", xdoc.DocumentElement.NamespaceURI); 

       //get the source 
       var worksheetSource = xdoc.SelectSingleNode("/default:pivotCacheDefinition/default:cacheSource/default:worksheetSource", nsm); 

       //Clear the attributes 
       var att = worksheetSource.Attributes["ref"]; 
       worksheetSource.Attributes.Remove(att); 

       att = worksheetSource.Attributes["sheet"]; 
       worksheetSource.Attributes.Remove(att); 

       //Create the new attribute for table 
       att = xdoc.CreateAttribute("name"); 
       att.Value = tablename; 
       worksheetSource.Attributes.Append(att); 

       xdoc.Save(newstream); 
      } 

      orgstream.Close(); 
      newstream.Flush(); 
      newstream.Close(); 
     }); 
    } 

    return cacheFound; 

} 

這裏是如何使用它:

//Throw in some data 
var datatable = new DataTable("tblData"); 
datatable.Columns.AddRange(new[] 
{ 
    new DataColumn("Col1", typeof (int)), new DataColumn("Col2", typeof (int)), new DataColumn("Col3", typeof (object)) 
}); 

for (var i = 0; i < 10; i++) 
{ 
    var row = datatable.NewRow(); 
    row[0] = i; row[1] = i*10; row[2] = Path.GetRandomFileName(); 
    datatable.Rows.Add(row); 
} 

const string tablename = "PivotTableSource"; 
using (var pck = new ExcelPackage()) 
{ 
    var workbook = pck.Workbook; 

    var source = workbook.Worksheets.Add("source"); 
    source.Cells.LoadFromDataTable(datatable, true); 
    var datacells = source.Cells["A1:C11"]; 

    source.Tables.Add(datacells, tablename); 

    var pivotsheet = workbook.Worksheets.Add("pivot"); 
    pivotsheet.PivotTables.Add(pivotsheet.Cells["A1"], datacells, "PivotTable1"); 

    using (var orginalzip = new ZipArchive(new MemoryStream(pck.GetAsByteArray()), ZipArchiveMode.Read)) 
    { 
     var fi = new FileInfo(@"c:\temp\Pivot_From_Table.xlsx"); 
     if (fi.Exists) 
      fi.Delete(); 

     var result = orginalzip.SetCacheSourceToTable(fi, tablename, 1); 
     Console.Write("Cache source was updated: "); 
     Console.Write(result); 
    } 
} 
+0

在閱讀本文之前,我嘗試修改軟件包,並找到您在軟件包保存驗證周圍突出顯示的確切問題。你所提出的解決方案提供了一個非常好的替代方案,能夠很好地工作,並幫助我提高了知識水平非常感謝你。 – BadgersArise

相關問題