使用EPPLUS创build数据透视表filter

我正在使用EPPLUS excel库。 你有一个想法如何创build数据透视表与report filters, row label and values ? 一些简单的例子会很好。

这是一个简单的例子。 请注意,EEPlus无法进行页面过滤,所以您将不得不使用VBA,Excel Interop或XML操作(我在下面使用了XML)。 您可以将此代码放入EPPlus源代码下载的unit testing中,以便于testing:

 const string FORMATCURRENCY = "#,###;[Red](#,###)"; var file = new FileInfo(@"c:\temp\temp.xlsx"); if (file.Exists) file.Delete(); var pck = new ExcelPackage(file); var workbook = pck.Workbook; var worksheet = workbook.Worksheets.Add("newsheet"); //The data worksheet.Cells["A20"].Value = "Col1"; worksheet.Cells["A21"].Value = "sdf"; worksheet.Cells["A22"].Value = "wer"; worksheet.Cells["A23"].Value = "ghgh"; worksheet.Cells["A24"].Value = "sdf"; worksheet.Cells["A25"].Value = "wer"; worksheet.Cells["A26"].Value = "ghgh"; worksheet.Cells["A27"].Value = "sdf"; worksheet.Cells["A28"].Value = "wer"; worksheet.Cells["A29"].Value = "ghgh"; worksheet.Cells["B20"].Value = "Col2"; worksheet.Cells["B21"].Value = "Group A"; worksheet.Cells["B22"].Value = "Group B"; worksheet.Cells["B23"].Value = "Group A"; worksheet.Cells["B24"].Value = "Group C"; worksheet.Cells["B25"].Value = "Group A"; worksheet.Cells["B26"].Value = "Group B"; worksheet.Cells["B27"].Value = "Group C"; worksheet.Cells["B28"].Value = "Group C"; worksheet.Cells["B29"].Value = "Group A"; worksheet.Cells["C20"].Value = "Col3"; worksheet.Cells["C21"].Value = 453; worksheet.Cells["C22"].Value = 634; worksheet.Cells["C23"].Value = 274; worksheet.Cells["C24"].Value = 453; worksheet.Cells["C25"].Value = 634; worksheet.Cells["C26"].Value = 274; worksheet.Cells["C27"].Value = 453; worksheet.Cells["C28"].Value = 634; worksheet.Cells["C29"].Value = 274; worksheet.Cells["D20"].Value = "Col4"; worksheet.Cells["D21"].Value = 686468; worksheet.Cells["D22"].Value = 996440; worksheet.Cells["D23"].Value = 185780; worksheet.Cells["D24"].Value = 686468; worksheet.Cells["D25"].Value = 996440; worksheet.Cells["D26"].Value = 185780; worksheet.Cells["D27"].Value = 686468; worksheet.Cells["D28"].Value = 996440; worksheet.Cells["D29"].Value = 185780; //The pivot table var pivotTable = worksheet.PivotTables.Add(worksheet.Cells["A4"], worksheet.Cells["A20:D29"], "test"); //The label row field pivotTable.RowFields.Add(pivotTable.Fields["Col1"]); pivotTable.DataOnRows = false; //The data fields var field = pivotTable.DataFields.Add(pivotTable.Fields["Col3"]); field.Name = "Sum of Col2"; field.Function = DataFieldFunctions.Sum; field.Format = FORMATCURRENCY; field = pivotTable.DataFields.Add(pivotTable.Fields["Col4"]); field.Name = "Sum of Col3"; field.Function = DataFieldFunctions.Sum; field.Format = FORMATCURRENCY; //The page field pivotTable.PageFields.Add(pivotTable.Fields["Col2"]); var xdCacheDefinition = pivotTable.CacheDefinition.CacheDefinitionXml; var xeCacheFields = xdCacheDefinition.FirstChild["cacheFields"]; if (xeCacheFields == null) return; //To filter, add items to the Cache Definition via XML var count = 0; var assetfieldidx = -1; foreach (XmlElement cField in xeCacheFields) { var att = cField.Attributes["name"]; if (att != null && att.Value == "Col2" ) { assetfieldidx = count; var sharedItems = cField.GetElementsByTagName("sharedItems")[0] as XmlElement; if(sharedItems == null) continue; //set the collection attributes sharedItems.RemoveAllAttributes(); att = xdCacheDefinition.CreateAttribute("count"); att.Value = "3"; sharedItems.Attributes.Append(att); //create and add the item var item = xdCacheDefinition.CreateElement("s", sharedItems.NamespaceURI); att = xdCacheDefinition.CreateAttribute("v"); att.Value = "Group A"; item.Attributes.Append(att); sharedItems.AppendChild(item); item = xdCacheDefinition.CreateElement("s", sharedItems.NamespaceURI); att = xdCacheDefinition.CreateAttribute("v"); att.Value = "Group B"; item.Attributes.Append(att); sharedItems.AppendChild(item); item = xdCacheDefinition.CreateElement("s", sharedItems.NamespaceURI); att = xdCacheDefinition.CreateAttribute("v"); att.Value = "Group C"; item.Attributes.Append(att); sharedItems.AppendChild(item); break; } count++; } //Now go back to the main pivot table xml and add the cross references to complete filtering var xdPivotTable = pivotTable.PivotTableXml; var xdPivotFields = xdPivotTable.FirstChild["pivotFields"]; if (xdPivotFields == null) return; count = 0; foreach (XmlElement pField in xdPivotFields) { //Find the asset type field if (count == assetfieldidx) { var att = xdPivotTable.CreateAttribute("multipleItemSelectionAllowed"); att.Value = "1"; pField.Attributes.Append(att); var items = pField.GetElementsByTagName("items")[0] as XmlElement; items.RemoveAll(); att = xdPivotTable.CreateAttribute("count"); att.Value = "4"; items.Attributes.Append(att); pField.AppendChild(items); //Add the classes to the fields item collection for (var i = 0; i < 3; i++) { var item = xdPivotTable.CreateElement("item", items.NamespaceURI); att = xdPivotTable.CreateAttribute("x"); att.Value = i.ToString(CultureInfo.InvariantCulture); item.Attributes.Append(att); //Turn of the Cash class in the fielder if (i == 1) { att = xdPivotTable.CreateAttribute("h"); att.Value = "1"; item.Attributes.Append(att); } items.AppendChild(item); } //Add the default var defaultitem = xdPivotTable.CreateElement("item", items.NamespaceURI); att = xdPivotTable.CreateAttribute("t"); att.Value = "default"; defaultitem.Attributes.Append(att); items.AppendChild(defaultitem); break; } count++; } pck.Save(); 

对不起,所有的编辑,但我一直在这个工作了一会儿,当我偶然发现这个问题。 我创build了一个扩展方法只是为了应用一个filter。 给它的字段名称(它假定有一个包含列名称的标题行),要应用的filter和包含数据的工作表,如果没有数据工作表被传入,它将只是数据透视表工作表。做了基本的testing,所以你应该QA:

 public static bool FilterField(this ExcelPivotTable pivotTable, string pageFieldName, IEnumerable<object> filters, ExcelWorksheet dataWorksheet = null) { //set the worksheet var ws = dataWorksheet ?? pivotTable.WorkSheet; //Set the cache definitions and cache fields var xdCacheDefinition = pivotTable.CacheDefinition.CacheDefinitionXml; var xeCacheFields = xdCacheDefinition.FirstChild["cacheFields"]; if (xeCacheFields == null) return false; //Go the field list in the definitions, note the field idx and valuesfor var count = 0; var fieldIndex = -1; List<object> fieldValues = null; foreach (XmlElement cField in xeCacheFields) { var att = cField.Attributes["name"]; if (att != null && att.Value.Equals(pageFieldName, StringComparison.OrdinalIgnoreCase)) { //store the field data fieldIndex = count; var dataddress = new ExcelAddress(pivotTable.CacheDefinition.SourceRange.Address); var valueHeader = ws .Cells[dataddress.Start.Row, dataddress.Start.Column, dataddress.Start.Row, dataddress.End.Column] .FirstOrDefault(cell => cell.Value.ToString().Equals(pageFieldName, StringComparison.OrdinalIgnoreCase)); if (valueHeader == null) return false; //Get the range minus the header row var valueObject = valueHeader.Offset(1, 0, dataddress.End.Row - dataddress.Start.Row, 1).Value; var values = (object[,])valueObject; fieldValues = values .Cast<object>() .Distinct() .ToList(); //kick back if the types are mixed if (fieldValues.FirstOrDefault(v => v is string) != null && fieldValues.FirstOrDefault(v => !(v is string)) != null) throw new NotImplementedException("Filter function does not (yet) support mixed parameter types"); //fill in the shared items for the field var sharedItems = cField.GetElementsByTagName("sharedItems")[0] as XmlElement; if (sharedItems == null) continue; //Reset the collection attributes sharedItems.RemoveAllAttributes(); //Handle numerics - assume all or nothing var isNumeric = fieldValues.FirstOrDefault(v => v is string) == null; if (isNumeric) { att = xdCacheDefinition.CreateAttribute("containsSemiMixedTypes"); att.Value = "0"; sharedItems.Attributes.Append(att); att = xdCacheDefinition.CreateAttribute("containsString"); att.Value = "0"; sharedItems.Attributes.Append(att); att = xdCacheDefinition.CreateAttribute("containsNumber"); att.Value = "1"; sharedItems.Attributes.Append(att); att = xdCacheDefinition.CreateAttribute("containsInteger"); att.Value = fieldValues.Any(v => !(v is int || v is long)) ? "0" : "1"; sharedItems.Attributes.Append(att); } //add the count att = xdCacheDefinition.CreateAttribute("count"); att.Value = fieldValues.Count.ToString(CultureInfo.InvariantCulture); sharedItems.Attributes.Append(att); //create and add the item foreach (var fieldvalue in fieldValues) { var item = xdCacheDefinition.CreateElement(isNumeric ? "n" : "s", sharedItems.NamespaceURI); att = xdCacheDefinition.CreateAttribute("v"); att.Value = fieldvalue.ToString(); item.Attributes.Append(att); sharedItems.AppendChild(item); } break; } count++; } if (fieldIndex == -1 || fieldValues == null) return false; //Now go back to the main pivot table xml and add the cross references to complete filtering var xdPivotTable = pivotTable.PivotTableXml; var xdPivotFields = xdPivotTable.FirstChild["pivotFields"]; if (xdPivotFields == null) return false; var filtervalues = filters.ToList(); count = 0; foreach (XmlElement pField in xdPivotFields) { //Find the asset type field if (count == fieldIndex) { var att = xdPivotTable.CreateAttribute("multipleItemSelectionAllowed"); att.Value = "1"; pField.Attributes.Append(att); var items = pField.GetElementsByTagName("items")[0] as XmlElement; if (items == null) return false; items.RemoveAll(); att = xdPivotTable.CreateAttribute("count"); att.Value = (fieldValues.Count + 1).ToString(CultureInfo.InvariantCulture); items.Attributes.Append(att); pField.AppendChild(items); //Add the classes to the fields item collection for (var i = 0; i < fieldValues.Count; i++) { var item = xdPivotTable.CreateElement("item", items.NamespaceURI); att = xdPivotTable.CreateAttribute("x"); att.Value = i.ToString(CultureInfo.InvariantCulture); item.Attributes.Append(att); if (filtervalues.Contains(fieldValues[i])) { att = xdPivotTable.CreateAttribute("h"); att.Value = "1"; item.Attributes.Append(att); } items.AppendChild(item); } //Add the default var defaultitem = xdPivotTable.CreateElement("item", items.NamespaceURI); att = xdPivotTable.CreateAttribute("t"); att.Value = "default"; defaultitem.Attributes.Append(att); items.AppendChild(defaultitem); break; } count++; } return true; } 

在上面的例子中使用它,你会做这样的事情:

 pivotTable.FilterField("Col2", new List<string> { "Group B" });