【问题标题】:Importing excel file with all the conditional formatting rules to epplus将具有所有条件格式规则的excel文件导入epplus
【发布时间】:2015-02-15 21:46:18
【问题描述】:

我有一个 excel 文件,其中包含大量数据以及基于单元格中值的图标集和数据栏。看起来像这样:

我想将此 Excel 工作表连同条件格式一起导入。有没有这方面的图书馆??我经历了这个http://www.sitecorecleveland.com/resources/blogs-posts/easy_excel_interaction_pt6,但它只导入数据而不是格式。

如果不可能的话,epplus 中是否有代码可以在 excel 表中包含这些图标集。我可以有箭头、红绿灯等,但不能有这些。

【问题讨论】:

    标签: c# epplus epplus-4


    【解决方案1】:

    我认为 EPP 不支持在 Excel 文件的 xml 中存储为“工作簿扩展”的自定义条件格式。您可以将包含自定义格式的“extLst”的 xml 节点从一个工作表复制到另一个工作表。只需确保在您不想复制的节点中除了 cond 格式 xml 之外没有其他内容,在这种情况下,您必须只选择所需的子节点。

    为了测试,我创建了以下 excel 表 (temp.xlsx),只复制了值并保存到一个新文件 (temp2.​​xlsx):

    然后运行以下命令并成功复制格式:

    public void Custom_Condition_Copy_Test()
    {
        //http://stackoverflow.com/questions/28493050/importing-excel-file-with-all-the-conditional-formatting-rules-to-epplus
    
        //File with custom conditional formatting
        var existingFile = new FileInfo(@"c:\temp\temp.xlsx");
    
        //Copy of the file with the conditonal formatting removed
        var existingFile2 = new FileInfo(@"c:\temp\temp2.xlsx");
    
        using (var package = new ExcelPackage(existingFile))
        using (var package2 = new ExcelPackage(existingFile2))
        {
            //Make sure there are document element for the source
            var worksheet = package.Workbook.Worksheets.First();
            var xdoc = worksheet.WorksheetXml;
    
            if (xdoc.DocumentElement == null)
                return;
    
            //Make sure there are document element for the destination
            var worksheet2 = package2.Workbook.Worksheets.First();
            var xdoc2 = worksheet2.WorksheetXml;
    
            if (xdoc2.DocumentElement == null)
                return;
    
            //get the extension list node 'extLst' from the ws with the formatting 
            var extensionlistnode = xdoc
                .DocumentElement
                .GetElementsByTagName("extLst")[0];
    
            //Create the import node and append it to the end of the xml document
            var newnode = xdoc2.ImportNode(extensionlistnode, true);
            xdoc2.LastChild.AppendChild(newnode);
    
            package2.Save();
    
        }
    }
    

    可能想尝试一下,但这应该会让你接近。


    更新:基于 OP 评论。

    如果您希望能够添加自定义条件格式而不需要包含它的原始文件,我看到两个选项。

    选项 1,您以更“正确”的方式进行操作并使用 DocumentFormat.OpenXml 命名空间。但是,这将要求您拥有可用的 Office Open XML 库,这可能会或可能不会那么容易,具体取决于您运行它的环境。您可以从这里获取它http://www.microsoft.com/en-us/download/details.aspx?id=30425,它带有一个反射工具,可以生成你想要的代码:

    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Spreadsheet;
    using DocumentFormat.OpenXml;
    using X14 = DocumentFormat.OpenXml.Office2010.Excel;
    using Excel = DocumentFormat.OpenXml.Office.Excel;  
    
    ......
    
    WorksheetExtensionList worksheetExtensionList1 = new WorksheetExtensionList();
    
    WorksheetExtension worksheetExtension1 = new WorksheetExtension(){ Uri = "{78C0D931-6437-407d-A8EE-F0AAD7539E65}" };
    worksheetExtension1.AddNamespaceDeclaration("x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main");
    
    X14.ConditionalFormattings conditionalFormattings1 = new X14.ConditionalFormattings();
    
    X14.ConditionalFormatting conditionalFormatting1 = new X14.ConditionalFormatting();
    conditionalFormatting1.AddNamespaceDeclaration("xm", "http://schemas.microsoft.com/office/excel/2006/main");
    
    X14.ConditionalFormattingRule conditionalFormattingRule1 = new X14.ConditionalFormattingRule(){ Type = ConditionalFormatValues.IconSet, Priority = 2, Id = "{CD6B2710-0474-449D-881A-22CFE15D011D}" };
    
    X14.IconSet iconSet1 = new X14.IconSet(){ IconSetTypes = X14.IconSetTypeValues.FiveArrows, Custom = true };
    
    X14.ConditionalFormattingValueObject conditionalFormattingValueObject1 = new X14.ConditionalFormattingValueObject(){ Type = X14.ConditionalFormattingValueObjectTypeValues.Percent };
    Excel.Formula formula1 = new Excel.Formula();
    formula1.Text = "0";
    
    conditionalFormattingValueObject1.Append(formula1);
    
    X14.ConditionalFormattingValueObject conditionalFormattingValueObject2 = new X14.ConditionalFormattingValueObject(){ Type = X14.ConditionalFormattingValueObjectTypeValues.Percent };
    Excel.Formula formula2 = new Excel.Formula();
    formula2.Text = "20";
    
    conditionalFormattingValueObject2.Append(formula2);
    
    X14.ConditionalFormattingValueObject conditionalFormattingValueObject3 = new X14.ConditionalFormattingValueObject(){ Type = X14.ConditionalFormattingValueObjectTypeValues.Percent };
    Excel.Formula formula3 = new Excel.Formula();
    formula3.Text = "40";
    
    conditionalFormattingValueObject3.Append(formula3);
    
    X14.ConditionalFormattingValueObject conditionalFormattingValueObject4 = new X14.ConditionalFormattingValueObject(){ Type = X14.ConditionalFormattingValueObjectTypeValues.Percent };
    Excel.Formula formula4 = new Excel.Formula();
    formula4.Text = "60";
    
    conditionalFormattingValueObject4.Append(formula4);
    
    X14.ConditionalFormattingValueObject conditionalFormattingValueObject5 = new X14.ConditionalFormattingValueObject(){ Type = X14.ConditionalFormattingValueObjectTypeValues.Percent };
    Excel.Formula formula5 = new Excel.Formula();
    formula5.Text = "80";
    
    conditionalFormattingValueObject5.Append(formula5);
    X14.ConditionalFormattingIcon conditionalFormattingIcon1 = new X14.ConditionalFormattingIcon(){ IconSet = X14.IconSetTypeValues.ThreeSymbols, IconId = (UInt32Value)0U };
    X14.ConditionalFormattingIcon conditionalFormattingIcon2 = new X14.ConditionalFormattingIcon(){ IconSet = X14.IconSetTypeValues.ThreeTrafficLights1, IconId = (UInt32Value)0U };
    X14.ConditionalFormattingIcon conditionalFormattingIcon3 = new X14.ConditionalFormattingIcon(){ IconSet = X14.IconSetTypeValues.ThreeTriangles, IconId = (UInt32Value)0U };
    X14.ConditionalFormattingIcon conditionalFormattingIcon4 = new X14.ConditionalFormattingIcon(){ IconSet = X14.IconSetTypeValues.ThreeTriangles, IconId = (UInt32Value)1U };
    X14.ConditionalFormattingIcon conditionalFormattingIcon5 = new X14.ConditionalFormattingIcon(){ IconSet = X14.IconSetTypeValues.ThreeTriangles, IconId = (UInt32Value)2U };
    
    iconSet1.Append(conditionalFormattingValueObject1);
    iconSet1.Append(conditionalFormattingValueObject2);
    iconSet1.Append(conditionalFormattingValueObject3);
    iconSet1.Append(conditionalFormattingValueObject4);
    iconSet1.Append(conditionalFormattingValueObject5);
    iconSet1.Append(conditionalFormattingIcon1);
    iconSet1.Append(conditionalFormattingIcon2);
    iconSet1.Append(conditionalFormattingIcon3);
    iconSet1.Append(conditionalFormattingIcon4);
    iconSet1.Append(conditionalFormattingIcon5);
    
    conditionalFormattingRule1.Append(iconSet1);
    Excel.ReferenceSequence referenceSequence1 = new Excel.ReferenceSequence();
    referenceSequence1.Text = "A1:C201";
    
    conditionalFormatting1.Append(conditionalFormattingRule1);
    conditionalFormatting1.Append(referenceSequence1);
    
    conditionalFormattings1.Append(conditionalFormatting1);
    
    worksheetExtension1.Append(conditionalFormattings1);
    
    worksheetExtensionList1.Append(worksheetExtension1);
    ....
    worksheet1.Append(worksheetExtensionList1);
    

    选项 2 将按照您的要求进行操作并执行字符串操作。这要容易得多,但它有点脏,因为你在搞乱字符串而不是对象,但如果你唯一需要设置的是看起来不那么糟糕的单元格范围。我用上面的测试方法提取了带有= extensionlistnode.OuterXml的字符串:

    [TestMethod]
    public void Custom_Condition_From_String_Test()
    {
        //http://stackoverflow.com/questions/28493050/importing-excel-file-with-all-the-conditional-formatting-rules-to-epplus
    
        //Throw in some data
        var datatable = new DataTable("tblData");
        datatable.Columns.Add(new DataColumn("Col1", typeof(int)));
        datatable.Columns.Add(new DataColumn("Col2", typeof(int)));
        datatable.Columns.Add(new DataColumn("Col3", typeof(int)));
    
        for (var i = 0; i < 20; i++)
        {
            var row = datatable.NewRow();
            row["Col1"] = i;
            row["Col2"] = i * 10;
            row["Col3"] = i * 100;
            datatable.Rows.Add(row);
        }
    
        //Copy of the file with the conditonal formatting removed
        var existingFile2 = new FileInfo(@"c:\temp\temp2.xlsx");
        if (existingFile2.Exists)
            existingFile2.Delete();
    
        using (var package2 = new ExcelPackage(existingFile2))
        {
            //Add the data
            var ws = package2.Workbook.Worksheets.Add("Content");
            ws.Cells.LoadFromDataTable(datatable, true);
    
            //The XML String extracted from the orginal excel doc using '= extensionlistnode.OuterXml'
            var cellrange = "A1:C201";
            var rawxml = String.Format(
                "<extLst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><ext uri=\"{{78C0D931-6437-407d-A8EE-F0AAD7539E65}}\" xmlns:x14=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\"><x14:conditionalFormattings><x14:conditionalFormatting xmlns:xm=\"http://schemas.microsoft.com/office/excel/2006/main\"><x14:cfRule type=\"iconSet\" priority=\"2\" id=\"{{CD6B2710-0474-449D-881A-22CFE15D011D}}\"><x14:iconSet iconSet=\"5Arrows\" custom=\"1\"><x14:cfvo type=\"percent\"><xm:f>0</xm:f></x14:cfvo><x14:cfvo type=\"percent\"><xm:f>20</xm:f></x14:cfvo><x14:cfvo type=\"percent\"><xm:f>40</xm:f></x14:cfvo><x14:cfvo type=\"percent\"><xm:f>60</xm:f></x14:cfvo><x14:cfvo type=\"percent\"><xm:f>80</xm:f></x14:cfvo><x14:cfIcon iconSet=\"3Symbols\" iconId=\"0\" /><x14:cfIcon iconSet=\"3TrafficLights1\" iconId=\"0\" /><x14:cfIcon iconSet=\"3Triangles\" iconId=\"0\" /><x14:cfIcon iconSet=\"3Triangles\" iconId=\"1\" /><x14:cfIcon iconSet=\"3Triangles\" iconId=\"2\" /></x14:iconSet></x14:cfRule><xm:sqref>{0}</xm:sqref></x14:conditionalFormatting></x14:conditionalFormattings></ext></extLst>"
                , cellrange);
    
            var newxdoc = new XmlDocument();
            newxdoc.LoadXml(rawxml);
    
            //Create the import node and append it to the end of the xml document
            var xdoc2 = ws.WorksheetXml;
            var newnode = xdoc2.ImportNode(newxdoc.FirstChild, true);
            xdoc2.LastChild.AppendChild(newnode);
    
            package2.Save();
        }
    }
    

    【讨论】:

    • 您提供的答案效果很好,是一个很好的起点。但是,是否可以让包含 file1 格式的 xml 将其初始化为测试方法中的字符串,而不必使用 file1,我们可以使用此字符串修改 file2 的 innerxml?因为,在上面的代码中,如果在 excel 中对 c3:f4 进行了格式化,那么它会对 file2 做同样的事情。也就是说,它不会格式化 f23 的数据,例如?
    • @sanmis 如果我理解您的要求,您想要进行字符串操作,这样您就不需要访问第一个文件而不是获取原始 XML?请参阅上面的最后一次编辑。
    • 正是我想要的。干杯。
    猜你喜欢
    • 2015-04-08
    • 1970-01-01
    • 1970-01-01
    • 2014-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多