为什么在这个例子中追加AutoFilter会破坏我的excel文件?

您好我使用下面的方法来应用自动filter:

public static void ApplyAutofilter(string fileName, string sheetName, string reference) { using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true)) { IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>().Where(s => s.Name == sheetName); var arrSheets = sheets as Sheet[] ?? sheets.ToArray(); string relationshipId = arrSheets.First().Id.Value; var worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(relationshipId); var autoFilter = new AutoFilter() { Reference = reference }; worksheetPart.Worksheet.Append(autoFilter); worksheetPart.Worksheet.Save(); } } 

我有这个简单的Excel工作表:

在这里输入图像说明

当我把这个方法称为:

 ApplyAutofilter(@".\Test.xlsx", "Foo", "A0:A200"); 

要么

 ApplyAutofilter(@".\Test.xlsx", "Foo", "A1:A200"); 

filter没有被应用,当我尝试打开它后,文件被破坏:

在这里输入图像描述

问题:任何想法如何将这个autofiler应用到excel表单而不会破坏它?

发生这种情况是因为您在XML中编写autoFilter元素的位置。 我打开了一个已经运行代码的文件,并在Open XML Productivity Tool中将其打开 。 这表明错误是

错误消息:意外的子元素

从这里查看 ECMA-376标准, Worksheet的XML如下所示:

 <xsd:complexType name="CT_Worksheet"> <xsd:sequence> <xsd:element name="sheetPr" type="CT_SheetPr" minOccurs="0" maxOccurs="1"/> <xsd:element name="dimension" type="CT_SheetDimension" minOccurs="0" maxOccurs="1"/> <xsd:element name="sheetViews" type="CT_SheetViews" minOccurs="0" maxOccurs="1"/> <xsd:element name="sheetFormatPr" type="CT_SheetFormatPr" minOccurs="0" maxOccurs="1"/> <xsd:element name="cols" type="CT_Cols" minOccurs="0" maxOccurs="unbounded"/> <xsd:element name="sheetData" type="CT_SheetData" minOccurs="1" maxOccurs="1"/> <xsd:element name="sheetCalcPr" type="CT_SheetCalcPr" minOccurs="0" maxOccurs="1"/> <xsd:element name="sheetProtection" type="CT_SheetProtection" minOccurs="0" maxOccurs="1"/> <xsd:element name="protectedRanges" type="CT_ProtectedRanges" minOccurs="0" maxOccurs="1"/> <xsd:element name="scenarios" type="CT_Scenarios" minOccurs="0" maxOccurs="1"/> <xsd:element name="autoFilter" type="CT_AutoFilter" minOccurs="0" maxOccurs="1"/> <xsd:element name="sortState" type="CT_SortState" minOccurs="0" maxOccurs="1"/> <xsd:element name="dataConsolidate" type="CT_DataConsolidate" minOccurs="0" maxOccurs="1"/> <xsd:element name="customSheetViews" type="CT_CustomSheetViews" minOccurs="0" maxOccurs="1"/> <xsd:element name="mergeCells" type="CT_MergeCells" minOccurs="0" maxOccurs="1"/> <xsd:element name="phoneticPr" type="CT_PhoneticPr" minOccurs="0" maxOccurs="1"/> <xsd:element name="conditionalFormatting" type="CT_ConditionalFormatting" minOccurs="0" maxOccurs="unbounded"/> <xsd:element name="dataValidations" type="CT_DataValidations" minOccurs="0" maxOccurs="1"/> <xsd:element name="hyperlinks" type="CT_Hyperlinks" minOccurs="0" maxOccurs="1"/> <xsd:element name="printOptions" type="CT_PrintOptions" minOccurs="0" maxOccurs="1"/> <xsd:element name="pageMargins" type="CT_PageMargins" minOccurs="0" maxOccurs="1"/> <xsd:element name="pageSetup" type="CT_PageSetup" minOccurs="0" maxOccurs="1"/> <xsd:element name="headerFooter" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> <xsd:element name="rowBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/> <xsd:element name="colBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/> <xsd:element name="customProperties" type="CT_CustomProperties" minOccurs="0" maxOccurs="1"/> <xsd:element name="cellWatches" type="CT_CellWatches" minOccurs="0" maxOccurs="1"/> <xsd:element name="ignoredErrors" type="CT_IgnoredErrors" minOccurs="0" maxOccurs="1"/> <xsd:element name="smartTags" type="CT_SmartTags" minOccurs="0" maxOccurs="1"/> <xsd:element name="drawing" type="CT_Drawing" minOccurs="0" maxOccurs="1"/> <xsd:element name="drawingHF" type="CT_DrawingHF" minOccurs="0" maxOccurs="1"/> <xsd:element name="picture" type="CT_SheetBackgroundPicture" minOccurs="0" maxOccurs="1"/> <xsd:element name="oleObjects" type="CT_OleObjects" minOccurs="0" maxOccurs="1"/> <xsd:element name="controls" type="CT_Controls" minOccurs="0" maxOccurs="1"/> <xsd:element name="webPublishItems" type="CT_WebPublishItems" minOccurs="0" maxOccurs="1"/> <xsd:element name="tableParts" type="CT_TableParts" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> 

请注意,这是一个sequence所以项目的sequence很重要。 在我上面的示例文件中, autoFilter元素被添加到与上述模式相反的pageMargins元素之后。

更改代码以将autoFilter元素写入正确的位置将修复您的代码。 我不确定这是否是最有效的方法,但这应该起作用。 它本质上是向后workbook的子元素,直到findautoFilter可以在之后的第一个元素。 一旦发现它使用InsertAfter方法将autoFilter插入到正确的位置:

 public static void ApplyAutofilter(string fileName, string sheetName, string reference) { using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true)) { IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>().Where(s => s.Name == sheetName); var arrSheets = sheets as Sheet[] ?? sheets.ToArray(); string relationshipId = arrSheets.First().Id.Value; var worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(relationshipId); var autoFilter = new AutoFilter() { Reference = reference }; OpenXmlElement preceedingElement = GetPreceedingElement(worksheetPart); worksheetPart.Worksheet.InsertAfter(autoFilter, preceedingElement); worksheetPart.Worksheet.Save(); } } public static OpenXmlElement GetPreceedingElement(WorksheetPart worksheetPart) { List<Type> elements = new List<Type>() { typeof(Scenarios), typeof(ProtectedRanges), typeof(SheetProtection), typeof(SheetCalculationProperties), typeof(SheetData) }; OpenXmlElement preceedingElement = null; foreach (var item in worksheetPart.Worksheet.ChildElements.Reverse()) { if (elements.Contains(item.GetType())) { preceedingElement = item; break; } } return preceedingElement; }