pen*_*ake 5 .net c# excel openxml openxml-sdk
您好我使用以下方法来应用自动筛选:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
我有这个简单的Excel表格:

问题在于我将此方法称为:
ApplyAutofilter(@".\Test.xlsx", "Foo", "A0:A200");
Run Code Online (Sandbox Code Playgroud)
要么
ApplyAutofilter(@".\Test.xlsx", "Foo", "A1:A200");
Run Code Online (Sandbox Code Playgroud)
在我尝试打开之后,未应用过滤器并且文件已损坏:

问题:有没有想过如何将这个自动加载器应用到excel表而不会破坏它?
出现这种情况是因为在那里你正在写的autoFilter在XML元素.我打开了一个运行代码的文件,并在Open XML Productivity Tool中打开它.这表明错误是

从这里查看 ECMA-376标准,XML Worksheet看起来像这样:
<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>
Run Code Online (Sandbox Code Playgroud)
请注意,这是sequence项目的顺序.在上面的示例文件中,autoFilter元素是在pageMargins与上述模式相反的元素之后添加的.
更改代码以将autoFilter元素写入正确的位置可修复代码.我不确定这是否是最有效的方式,但这应该有效.它本质上是向后工作的子元素,workbook直到它找到可以追随的第一个元素autoFilter.一旦发现它使用该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;
}
Run Code Online (Sandbox Code Playgroud)