2015-10-22 50 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

相关问题