为什么在这个例子中追加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; }