Skip to content

Instantly share code, notes, and snippets.

@fiddyschmitt
Last active March 13, 2022 02:21
Show Gist options
  • Save fiddyschmitt/3929e6305814088e3b9f5f0790c7e96f to your computer and use it in GitHub Desktop.
Save fiddyschmitt/3929e6305814088e3b9f5f0790c7e96f to your computer and use it in GitHub Desktop.
var columnFilters = new[]
{
new {SheetName = "Sheet1", ColumnName = "FirstName", Values = new [] { "Bob", "John"}},
new {SheetName = "Sheet1", ColumnName = "Age", Values = new [] { 30"}},
}.ToList();
//Apply filters
using (var pck = new ExcelPackage(new FileInfo(parametricsLogFilename)))
{
columnFilters.ForEach(columnFilter =>
{
//Find the worksheet
var worksheet = pck.Workbook.Worksheets.FirstOrDefault(sheet => sheet.Name.Equals(columnFilter.SheetName));
if (worksheet == null) return;
//Get the column names
var columnInfos = worksheet
.Cells[worksheet.Dimension.Start.Row, worksheet.Dimension.Start.Column, 1, worksheet.Dimension.End.Column]
.Select((cell, index) => new
{
ColumnCell = cell,
Index = index
})
.ToList();
//Find the column
var columnInfo = columnInfos.FirstOrDefault(info => info.ColumnCell.Value.Equals(columnFilter.ColumnName));
if (columnInfo == null) return;
//Get reference to the worksheet xml for proper namespace
var xdoc = worksheet.WorksheetXml;
var nsm = new XmlNamespaceManager(xdoc.NameTable);
nsm.AddNamespace("default", xdoc.DocumentElement.NamespaceURI);
//Create the filters themselves
var filterNodes = columnFilter.Values.Select(filterValue =>
{
var filterNode = xdoc.CreateNode(XmlNodeType.Element, "filter", xdoc.DocumentElement.NamespaceURI);
var filterAtt = xdoc.CreateAttribute("val");
filterAtt.Value = filterValue;
filterNode.Attributes.Append(filterAtt);
return filterNode;
})
.ToList();
//Add filters to the collection
var filtersNode = xdoc.CreateNode(XmlNodeType.Element, "filters", xdoc.DocumentElement.NamespaceURI);
filterNodes.ForEach(filterNode =>
{
filtersNode.AppendChild(filterNode);
});
//Create the parent filter container
var filterColumnNode = xdoc.CreateNode(XmlNodeType.Element, "filterColumn", xdoc.DocumentElement.NamespaceURI);
var att = xdoc.CreateAttribute("colId");
att.Value = $"{columnInfo.Index}";
filterColumnNode.Attributes.Append(att);
filterColumnNode.AppendChild(filtersNode);
//Now add it to the autoFilters node
var autoFilter = xdoc.SelectSingleNode("/default:worksheet/default:autoFilter", nsm);
autoFilter.AppendChild(filterColumnNode);
//Get a list of cells in the column. We can't just iterate over worksheet.Cells because if a column is completely blank, the IEnumerable is empty
var rawCellsInColumn = (object[,])worksheet.Cells[worksheet.Dimension.Start.Row, columnInfo.Index + 1, worksheet.Dimension.End.Row, columnInfo.Index + 1].Value;
var cellsInColumn = new List<(int RowNumber, object Value)>();
for (int rowNumber = 0; rowNumber < rawCellsInColumn.GetLength(0); rowNumber++)
{
cellsInColumn.Add((rowNumber, rawCellsInColumn[rowNumber, 0]));
}
//Have to manually hide rows based on criteria
var rowsToHide = cellsInColumn
.Skip(1)
.Where(cell => cell.Value == null || !columnFilter.Values.Contains(cell.Value))
.ToList();
rowsToHide
.ForEach(cell => worksheet.Row(cell.RowNumber + 1).Hidden = true);
});
pck.Save();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment