【问题标题】:Create Pivot Table Filters With EPPLUS使用 EPPLUS 创建数据透视表过滤器
【发布时间】:2014-09-12 12:26:21
【问题描述】:

我正在使用EPPLUS excel 库。您知道如何使用 report filters, row label and values 创建数据透视表吗?一些简单的例子会很好。

【问题讨论】:

    标签: c# excel epplus


    【解决方案1】:

    这是一个简单的例子。请注意,EEPlus 不具备执行页面过滤器的功能,因此您必须使用(按难度排序)VBA、Excel 互操作或 XML 操作(我在下面使用了 XML)。您可以将此代码放入 EPPlus 源下载的单元测试中,以便于测试:

    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();
    

    很抱歉所有的编辑,但当我偶然发现这个问题时,我已经研究了一段时间。我创建了一个仅用于应用过滤器的扩展方法。给它字段名称(它假设有一个标题行连接列名),您要应用的过滤器以及包含数据的工作表,或者如果没有传入数据工作表,它将只是数据透视表工作表。它有已完成基本测试,因此您应该进行 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" });
    

    【讨论】:

      猜你喜欢
      • 2013-05-16
      • 1970-01-01
      • 2017-02-20
      • 2016-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-24
      • 1970-01-01
      相关资源
      最近更新 更多