| /*************************************************************************** |
| |
| Copyright (c) Microsoft Corporation 2012-2015. |
| |
| This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here: |
| |
| http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx |
| |
| Published at http://OpenXmlDeveloper.org |
| Resource Center and Documentation: http://openxmldeveloper.org/wiki/w/wiki/powertools-for-open-xml.aspx |
| |
| Developer: Eric White |
| Blog: http://www.ericwhite.com |
| Twitter: @EricWhiteDev |
| Email: eric@ericwhite.com |
| |
| ***************************************************************************/ |
| |
| using System; |
| using System.Text; |
| using System.Collections.Generic; |
| using System.Linq; |
| using System.Xml.Linq; |
| using DocumentFormat.OpenXml.Packaging; |
| using System.Xml; |
| using ExcelFormula; |
| |
| namespace OpenXmlPowerTools |
| { |
| // Classes for "bulk load" of a spreadsheet |
| public class MemorySpreadsheet |
| { |
| private SortedList<int, MemoryRow> rowList; |
| |
| public MemorySpreadsheet() |
| { |
| rowList = new SortedList<int, MemoryRow>(); |
| } |
| |
| public void SetCellValue(int row, int column, object value) |
| { |
| if (!rowList.ContainsKey(row)) |
| rowList.Add(row, new MemoryRow(row)); |
| MemoryRow mr = rowList[row]; |
| mr.SetCell(new MemoryCell(column, value)); |
| } |
| |
| public void SetCellValue(int row, int column, object value, int styleIndex) |
| { |
| if (!rowList.ContainsKey(row)) |
| rowList.Add(row, new MemoryRow(row)); |
| MemoryRow mr = rowList[row]; |
| mr.SetCell(new MemoryCell(column, value, styleIndex)); |
| } |
| |
| public object GetCellValue(int row, int column) |
| { |
| if (!rowList.ContainsKey(row)) |
| return null; |
| MemoryCell cell = rowList[row].GetCell(column); |
| if (cell == null) |
| return null; |
| return cell.GetValue(); |
| } |
| |
| public XElement GetElements() |
| { |
| XElement root = new XElement(S.sheetData); |
| foreach (KeyValuePair<int, MemoryRow> item in rowList) |
| root.Add(item.Value.GetElements()); |
| return root; |
| } |
| } |
| |
| public class MemoryRow |
| { |
| private int row; |
| private SortedList<int, MemoryCell> cellList; |
| |
| public MemoryRow(int Row) |
| { |
| row = Row; |
| cellList = new SortedList<int, MemoryCell>(); |
| } |
| |
| public MemoryCell GetCell(int column) |
| { |
| if (!cellList.ContainsKey(column)) |
| return null; |
| return cellList[column]; |
| } |
| |
| public void SetCell(MemoryCell cell) |
| { |
| if (cellList.ContainsKey(cell.GetColumn())) |
| cellList.Remove(cell.GetColumn()); |
| cellList.Add(cell.GetColumn(), cell); |
| } |
| |
| public XElement GetElements() |
| { |
| XElement root = new XElement(S.row, new XAttribute(NoNamespace.r, row)); |
| foreach (KeyValuePair<int, MemoryCell> item in cellList) |
| root.Add(item.Value.GetElements(row)); |
| return root; |
| } |
| } |
| |
| public class MemoryCell |
| { |
| private int column; |
| private object cellValue; |
| private int styleIndex; |
| |
| public MemoryCell(int col, object value) |
| { |
| column = col; |
| cellValue = value; |
| } |
| |
| public MemoryCell(int col, object value, int style) |
| { |
| column = col; |
| cellValue = value; |
| styleIndex = style; |
| } |
| |
| public int GetColumn() |
| { |
| return column; |
| } |
| public object GetValue() |
| { |
| return cellValue; |
| } |
| public int GetStyleIndex() |
| { |
| return styleIndex; |
| } |
| |
| public XElement GetElements(int row) |
| { |
| string cellReference = WorksheetAccessor.GetColumnId(column) + row.ToString(); |
| XElement newCell = null; |
| |
| if (cellValue is int || cellValue is double) |
| newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XElement(S.v, cellValue.ToString())); |
| else if (cellValue is bool) |
| newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XAttribute(NoNamespace.t, "b"), new XElement(S.v, (bool)cellValue ? "1" : "0")); |
| else if (cellValue is string) |
| { |
| newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XAttribute(NoNamespace.t, "inlineStr"), |
| new XElement(S._is, new XElement(S.t, cellValue.ToString()))); |
| } |
| if (newCell == null) |
| throw new ArgumentException("Invalid cell type."); |
| if (styleIndex != 0) |
| newCell.Add(new XAttribute(NoNamespace.s, styleIndex)); |
| |
| return newCell; |
| } |
| } |
| |
| // Static methods to modify worksheets in SpreadsheetML |
| public class WorksheetAccessor |
| { |
| private static XNamespace ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"; |
| private static XNamespace relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; |
| |
| // Finds the WorksheetPart by sheet name |
| public static WorksheetPart GetWorksheet(SpreadsheetDocument document, string worksheetName) |
| { |
| XDocument workbook = document.WorkbookPart.GetXDocument(); |
| return (WorksheetPart)document.WorkbookPart.GetPartById( |
| workbook.Root.Element(S.sheets).Elements(S.sheet).Where( |
| s => s.Attribute(NoNamespace.name).Value.ToLower().Equals(worksheetName.ToLower())) |
| .FirstOrDefault().Attribute(R.id).Value); |
| } |
| |
| // Creates a new worksheet with the specified name |
| public static WorksheetPart AddWorksheet(SpreadsheetDocument document, string worksheetName) |
| { |
| // Create the empty sheet |
| WorksheetPart worksheetPart = document.WorkbookPart.AddNewPart<WorksheetPart>(); |
| worksheetPart.PutXDocument(new XDocument( |
| new XElement(S.worksheet, new XAttribute("xmlns", S.s), new XAttribute(XNamespace.Xmlns + "r", R.r), |
| new XElement(S.sheetData)))); |
| XDocument wb = document.WorkbookPart.GetXDocument(); |
| |
| // Generate a unique sheet ID number |
| int sheetId = 1; |
| if (wb.Root.Element(S.sheets).Elements(S.sheet).Count() != 0) |
| sheetId = wb.Root.Element(S.sheets).Elements(S.sheet).Max(n => Convert.ToInt32(n.Attribute(NoNamespace.sheetId).Value)) + 1; |
| |
| // If name is null, generate a name based on the sheet ID |
| if (worksheetName == null) |
| worksheetName = "Sheet" + sheetId.ToString(); |
| |
| // Create the new sheet element in the workbook |
| wb.Root.Element(S.sheets).Add(new XElement(S.sheet, |
| new XAttribute(NoNamespace.name, worksheetName), |
| new XAttribute(NoNamespace.sheetId, sheetId), |
| new XAttribute(R.id, document.WorkbookPart.GetIdOfPart(worksheetPart)))); |
| document.WorkbookPart.PutXDocument(); |
| return worksheetPart; |
| } |
| |
| // Creates a new worksheet with the specified name and contents from a memory spreadsheet |
| public static void SetSheetContents(SpreadsheetDocument document, WorksheetPart worksheet, MemorySpreadsheet contents) |
| { |
| XDocument worksheetXDocument = worksheet.GetXDocument(); |
| worksheetXDocument.Root.Element(S.sheetData).ReplaceWith(contents.GetElements()); |
| worksheet.PutXDocument(); |
| } |
| |
| // Translates the column number to the column reference string (e.g. 1 -> A, 2-> B) |
| public static string GetColumnId(int columnNumber) |
| { |
| string result = ""; |
| do |
| { |
| result = ((char)((columnNumber - 1) % 26 + (int)'A')).ToString() + result; |
| columnNumber = (columnNumber - 1) / 26; |
| } while (columnNumber != 0); |
| return result; |
| } |
| |
| // Gets the value of the specified cell |
| // Returned object can be double/Double, int/Int32, bool/Boolean or string/String types |
| public static object GetCellValue(SpreadsheetDocument document, WorksheetPart worksheet, int column, int row) |
| { |
| XDocument worksheetXDocument = worksheet.GetXDocument(); |
| XElement cellValue = GetCell(worksheetXDocument, column, row); |
| |
| if (cellValue != null) |
| { |
| if (cellValue.Attribute(NoNamespace.t) == null) |
| { |
| string value = cellValue.Element(S.v).Value; |
| if (value.Contains(".")) |
| return Convert.ToDouble(value); |
| return Convert.ToInt32(value); |
| } |
| switch (cellValue.Attribute(NoNamespace.t).Value) |
| { |
| case "b": |
| return (cellValue.Element(S.v).Value == "1"); |
| case "s": |
| return GetSharedString(document, System.Convert.ToInt32(cellValue.Element(S.v).Value)); |
| case "inlineStr": |
| return cellValue.Element(S._is).Element(S.t).Value; |
| } |
| } |
| return null; |
| } |
| |
| // Finds the shared string using its index |
| private static string GetSharedString(SpreadsheetDocument document, int index) |
| { |
| XDocument sharedStringsXDocument = document.WorkbookPart.SharedStringTablePart.GetXDocument(); |
| return sharedStringsXDocument.Root.Elements().ElementAt<XElement>(index).Value; |
| } |
| |
| // Gets the cell element (c) for the specified cell |
| private static XElement GetCell(XDocument worksheet, int column, int row) |
| { |
| string cellReference = GetColumnId(column) + row.ToString(); |
| XElement rowElement = worksheet.Root |
| .Element(S.sheetData) |
| .Elements(S.row) |
| .Where(r => r.Attribute(NoNamespace.r).Value.Equals(row.ToString())).FirstOrDefault<XElement>(); |
| if (rowElement == null) |
| return null; |
| return rowElement.Elements(S.c).Where(c => c.Attribute(NoNamespace.r).Value.Equals(cellReference)).FirstOrDefault<XElement>(); |
| } |
| |
| // Sets the value for the specified cell |
| // The "value" must be double/Double, int/Int32, bool/Boolean or string/String type |
| public static void SetCellValue(SpreadsheetDocument document, WorksheetPart worksheet, int row, int column, object value) |
| { |
| XDocument worksheetXDocument = worksheet.GetXDocument(); |
| string cellReference = GetColumnId(column) + row.ToString(); |
| XElement newCell = null; |
| |
| if (value is int || value is double) |
| newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XElement(S.v, value.ToString())); |
| else if (value is bool) |
| newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XAttribute(NoNamespace.t, "b"), new XElement(S.v, (bool)value ? "1" : "0")); |
| else if (value is string) |
| { |
| newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XAttribute(NoNamespace.t, "inlineStr"), |
| new XElement(S._is, new XElement(S.t, value.ToString()))); |
| } |
| if (newCell == null) |
| throw new ArgumentException("Invalid cell type."); |
| |
| SetCell(worksheetXDocument, newCell); |
| } |
| |
| // Sets the specified cell |
| private static void SetCell(XDocument worksheetXDocument, XElement newCell) |
| { |
| int row; |
| int column; |
| string cellReference = newCell.Attribute(NoNamespace.r).Value; |
| GetRowColumn(cellReference, out row, out column); |
| |
| // Find the row containing the cell to add the value to |
| XElement rowElement = worksheetXDocument.Root |
| .Element(S.sheetData) |
| .Elements(S.row) |
| .Where(t => t.Attribute(NoNamespace.r).Value == row.ToString()) |
| .FirstOrDefault(); |
| |
| if (rowElement == null) |
| { |
| //row element does not exist |
| //create a new one |
| rowElement = CreateEmptyRow(row); |
| |
| //row elements must appear in order inside sheetData element |
| if (worksheetXDocument.Root.Element(S.sheetData).HasElements) |
| { //if there are more rows already defined at sheetData element |
| //find the row with the inmediate higher index for the row containing the cell to set the value to |
| XElement rowAfterElement = FindRowAfter(worksheetXDocument, row); |
| //if there is a row with an inmediate higher index already defined at sheetData |
| if (rowAfterElement != null) |
| { |
| //add the new row before the row with an inmediate higher index |
| rowAfterElement.AddBeforeSelf(rowElement); |
| } |
| else |
| { //this row is going to be the one with the highest index (add it as the last element for sheetData) |
| worksheetXDocument.Root.Element(S.sheetData).Elements(S.row).Last().AddAfterSelf(rowElement); |
| } |
| } |
| else |
| { //there are no other rows already defined at sheetData |
| //Add a new row elemento to sheetData |
| worksheetXDocument.Root.Element(S.sheetData).Add(rowElement); |
| } |
| |
| //Add the new cell to the row Element |
| rowElement.Add(newCell); |
| } |
| else |
| { |
| //row containing the cell to set the value to is already defined at sheetData |
| //look if cell already exist at that row |
| XElement currentCell = rowElement |
| .Elements(S.c) |
| .Where(t => t.Attribute(NoNamespace.r).Value == cellReference) |
| .FirstOrDefault(); |
| |
| if (currentCell == null) |
| { //cell element does not exist at row indicated as parameter |
| //find the inmediate right column for the cell to set the value to |
| XElement columnAfterXElement = FindColumAfter(worksheetXDocument, row, column); |
| if (columnAfterXElement != null) |
| { |
| //Insert the new cell before the inmediate right column |
| columnAfterXElement.AddBeforeSelf(newCell); |
| } |
| else |
| { //There is no inmediate right cell |
| //Add the new cell as the last element for the row |
| rowElement.Add(newCell); |
| } |
| } |
| else |
| { |
| //cell alreay exist |
| //replace the current cell with that with the new value |
| currentCell.ReplaceWith(newCell); |
| } |
| } |
| } |
| |
| // Finds the row element (r) with a higher number than the specified "row" number |
| private static XElement FindRowAfter(XDocument worksheet, int row) |
| { |
| return worksheet.Root |
| .Element(S.sheetData) |
| .Elements(S.row) |
| .FirstOrDefault(r => System.Convert.ToInt32(r.Attribute(NoNamespace.r).Value) > row); |
| } |
| |
| // Finds the cell element (c) in the specified row that is after the specified "column" number |
| private static XElement FindColumAfter(XDocument worksheet, int row, int column) |
| { |
| return worksheet.Root |
| .Element(S.sheetData) |
| .Elements(S.row) |
| .FirstOrDefault(r => System.Convert.ToInt32(r.Attribute(NoNamespace.r).Value) == row) |
| .Elements(S.c) |
| .FirstOrDefault(c => GetColumnNumber(c.Attribute(NoNamespace.r).Value) > GetColumnNumber(GetColumnId(column) + row)); |
| } |
| |
| // Converts the column reference string to a column number (e.g. A -> 1, B -> 2) |
| public static int GetColumnNumber(string cellReference) |
| { |
| int columnNumber = 0; |
| foreach (char c in cellReference) |
| { |
| if (Char.IsLetter(c)) |
| columnNumber = columnNumber * 26 + System.Convert.ToInt32(c) - System.Convert.ToInt32('A') + 1; |
| } |
| return columnNumber; |
| } |
| |
| // Converts a cell reference string into the row and column numbers for that cell |
| // e.g. G5 -> [row = 5, column = 7] |
| private static void GetRowColumn(string cellReference, out int row, out int column) |
| { |
| row = 0; |
| column = 0; |
| foreach (char c in cellReference) |
| { |
| if (Char.IsLetter(c)) |
| column = column * 26 + System.Convert.ToInt32(c) - System.Convert.ToInt32('A') + 1; |
| else |
| row = row * 10 + System.Convert.ToInt32(c) - System.Convert.ToInt32('0'); |
| } |
| } |
| |
| // Returns the row and column numbers and worksheet part for the named range |
| public static WorksheetPart GetRange(SpreadsheetDocument doc, string rangeName, out int startRow, out int startColumn, out int endRow, out int endColumn) |
| { |
| XDocument book = doc.WorkbookPart.GetXDocument(); |
| if (book.Root.Element(S.definedNames) == null) |
| throw new ArgumentException("Range name not found: " + rangeName); |
| XElement element = book.Root.Element(S.definedNames).Elements(S.definedName) |
| .Where(t => t.Attribute(NoNamespace.name).Value == rangeName).FirstOrDefault(); |
| if (element == null) |
| throw new ArgumentException("Range name not found: " + rangeName); |
| string sheetName = element.Value.Substring(0, element.Value.IndexOf('!')); |
| string range = element.Value.Substring(element.Value.IndexOf('!') + 1).Replace("$",""); |
| int colonIndex = range.IndexOf(':'); |
| GetRowColumn(range.Substring(0, colonIndex), out startRow, out startColumn); |
| GetRowColumn(range.Substring(colonIndex + 1), out endRow, out endColumn); |
| return GetWorksheet(doc, sheetName); |
| } |
| |
| // Sets the named range with the specified range of row and column numbers |
| public static void SetRange(SpreadsheetDocument doc, string rangeName, string sheetName, int startRow, int startColumn, int endRow, int endColumn) |
| { |
| XDocument book = doc.WorkbookPart.GetXDocument(); |
| if (book.Root.Element(S.definedNames) == null) |
| book.Root.Add(new XElement(S.definedNames)); |
| XElement element = book.Root.Element(S.definedNames).Elements(S.definedName) |
| .Where(t => t.Attribute(NoNamespace.name).Value == rangeName).FirstOrDefault(); |
| if (element == null) |
| { |
| element = new XElement(S.definedName, new XAttribute(NoNamespace.name, rangeName)); |
| book.Root.Element(S.definedNames).Add(element); |
| } |
| element.SetValue(String.Format("{0}!${1}${2}:${3}${4}", sheetName, GetColumnId(startColumn), startRow, GetColumnId(endColumn), endRow)); |
| doc.WorkbookPart.PutXDocument(); |
| } |
| |
| // Sets the end row for the named range |
| public static void UpdateRangeEndRow(SpreadsheetDocument doc, string rangeName, int lastRow) |
| { |
| // Update named range used by pivot table |
| XDocument book = doc.WorkbookPart.GetXDocument(); |
| XElement element = book.Root.Element(S.definedNames).Elements(S.definedName) |
| .Where(t => t.Attribute(NoNamespace.name).Value == rangeName).FirstOrDefault(); |
| if (element != null) |
| { |
| string original = element.Value; |
| element.SetValue(original.Substring(0, original.Length - 1) + lastRow.ToString()); |
| } |
| doc.WorkbookPart.PutXDocument(); |
| } |
| |
| // Creates an empty row element (r) with the specified row number |
| private static XElement CreateEmptyRow(int row) |
| { |
| return new XElement(S.row, new XAttribute(NoNamespace.r, row.ToString())); |
| } |
| |
| public static void ForceCalculateOnLoad(SpreadsheetDocument document) |
| { |
| XDocument book = document.WorkbookPart.GetXDocument(); |
| XElement element = book.Root.Element(S.calcPr); |
| if (element == null) |
| { |
| book.Root.Add(new XElement(S.calcPr)); |
| } |
| element.SetAttributeValue(NoNamespace.fullCalcOnLoad, "1"); |
| document.WorkbookPart.PutXDocument(); |
| } |
| |
| public static void FormulaReplaceSheetName(SpreadsheetDocument document, string oldName, string newName) |
| { |
| foreach (WorksheetPart sheetPart in document.WorkbookPart.WorksheetParts) |
| { |
| XDocument sheetDoc = sheetPart.GetXDocument(); |
| bool changed = false; |
| foreach (XElement formula in sheetDoc.Descendants(S.f)) |
| { |
| ParseFormula parser = new ParseFormula(formula.Value); |
| string newFormula = parser.ReplaceSheetName(oldName, newName); |
| if (newFormula != formula.Value) |
| { |
| formula.SetValue(newFormula); |
| changed = true; |
| } |
| } |
| if (changed) |
| { |
| sheetPart.PutXDocument(); |
| ForceCalculateOnLoad(document); |
| } |
| } |
| } |
| |
| // Copy all cells in the specified range to a new location |
| public static void CopyCellRange(SpreadsheetDocument document, WorksheetPart worksheet, int startRow, int startColumn, int endRow, int endColumn, |
| int toRow, int toColumn) |
| { |
| int rowOffset = toRow - startRow; |
| int columnOffset = toColumn - startColumn; |
| XDocument worksheetXDocument = worksheet.GetXDocument(); |
| for (int row = startRow; row <= endRow; row++) |
| for (int column = startColumn; column <= endColumn; column++) |
| { |
| XElement oldCell = GetCell(worksheetXDocument, column, row); |
| if (oldCell != null) |
| { |
| XElement newCell = new XElement(oldCell); |
| newCell.SetAttributeValue(NoNamespace.r, GetColumnId(column + columnOffset) + (row + rowOffset).ToString()); |
| XElement formula = newCell.Element(S.f); |
| if (formula != null) |
| { |
| ParseFormula parser = new ParseFormula(formula.Value); |
| formula.SetValue(parser.ReplaceRelativeCell(rowOffset, columnOffset)); |
| } |
| SetCell(worksheetXDocument, newCell); |
| } |
| } |
| worksheet.PutXDocument(); |
| ForceCalculateOnLoad(document); |
| } |
| |
| // Creates a pivot table in the specified sheet using the specified range name |
| // The new pivot table will not be configured with any fields in the rows, columns, filters or values |
| public static PivotTablePart CreatePivotTable(SpreadsheetDocument document, string rangeName, WorksheetPart sheet) |
| { |
| int startRow, startColumn, endRow, endColumn; |
| WorksheetPart sourceSheet = GetRange(document, rangeName, out startRow, out startColumn, out endRow, out endColumn); |
| |
| // Fill out pivotFields element (for PivotTablePart) and cacheFields element (for PivotTableCacheDefinitionPart) |
| // with an element for each column in the source range |
| XElement pivotFields = new XElement(S.pivotFields, new XAttribute(NoNamespace.count, (endColumn - startColumn + 1).ToString())); |
| XElement cacheFields = new XElement(S.cacheFields, new XAttribute(NoNamespace.count, (endColumn - startColumn + 1).ToString())); |
| for (int column = startColumn; column <= endColumn; column++) |
| { |
| pivotFields.Add(new XElement(S.pivotField, new XAttribute(NoNamespace.showAll, "0"))); |
| XElement sharedItems = new XElement(S.sharedItems); |
| // Determine numeric sharedItems values, if any |
| object value = GetCellValue(document, sourceSheet, column, startRow + 1); |
| if (value is double || value is Int32) |
| { |
| bool hasDouble = false; |
| double minValue = Convert.ToDouble(value); |
| double maxValue = Convert.ToDouble(value); |
| if (value is double) |
| hasDouble = true; |
| for (int row = startRow + 1; row <= endRow; row++) |
| { |
| value = GetCellValue(document, sourceSheet, column, row); |
| if (value is double) |
| hasDouble = true; |
| if (Convert.ToDouble(value) < minValue) |
| minValue = Convert.ToDouble(value); |
| if (Convert.ToDouble(value) > maxValue) |
| maxValue = Convert.ToDouble(value); |
| } |
| sharedItems.Add(new XAttribute(NoNamespace.containsSemiMixedTypes, "0"), |
| new XAttribute(NoNamespace.containsString, "0"), new XAttribute(NoNamespace.containsNumber, "1"), |
| new XAttribute(NoNamespace.minValue, minValue.ToString()), new XAttribute(NoNamespace.maxValue, maxValue.ToString())); |
| if (!hasDouble) |
| sharedItems.Add(new XAttribute(NoNamespace.containsInteger, "1")); |
| } |
| cacheFields.Add(new XElement(S.cacheField, new XAttribute(NoNamespace.name, GetCellValue(document, sourceSheet, column, startRow).ToString()), |
| new XAttribute(NoNamespace.numFmtId, "0"), sharedItems)); |
| } |
| |
| // Fill out pivotCacheRecords element (for PivotTableCacheRecordsPart) with an element |
| // for each row in the source range |
| XElement pivotCacheRecords = new XElement(S.pivotCacheRecords, new XAttribute("xmlns", S.s), |
| new XAttribute(XNamespace.Xmlns + "r", R.r), new XAttribute(NoNamespace.count, (endRow - startRow).ToString())); |
| for (int row = startRow + 1; row <= endRow; row++) |
| { |
| XElement r = new XElement(S.r); |
| |
| // Fill the record element with a value from each column in the source row |
| for (int column = startColumn; column <= endColumn; column++) |
| { |
| object value = GetCellValue(document, sourceSheet, column, row); |
| if (value is String) |
| r.Add(new XElement(S._s, new XAttribute(NoNamespace.v, value.ToString()))); |
| else |
| r.Add(new XElement(S.n, new XAttribute(NoNamespace.v, value.ToString()))); |
| } |
| pivotCacheRecords.Add(r); |
| } |
| |
| // Create pivot table parts with proper links |
| PivotTablePart pivotTable = sheet.AddNewPart<PivotTablePart>(); |
| PivotTableCacheDefinitionPart cacheDef = pivotTable.AddNewPart<PivotTableCacheDefinitionPart>(); |
| PivotTableCacheRecordsPart records = cacheDef.AddNewPart<PivotTableCacheRecordsPart>(); |
| document.WorkbookPart.AddPart<PivotTableCacheDefinitionPart>(cacheDef); |
| |
| // Set content for the PivotTableCacheRecordsPart and PivotTableCacheDefinitionPart |
| records.PutXDocument(new XDocument(pivotCacheRecords)); |
| cacheDef.PutXDocument(new XDocument(new XElement(S.pivotCacheDefinition, new XAttribute("xmlns", S.s), |
| new XAttribute(XNamespace.Xmlns + "r", R.r), new XAttribute(R.id, cacheDef.GetIdOfPart(records)), |
| new XAttribute(NoNamespace.recordCount, (endRow - startRow).ToString()), |
| new XElement(S.cacheSource, new XAttribute(NoNamespace.type, "worksheet"), |
| new XElement(S.worksheetSource, new XAttribute(NoNamespace.name, rangeName))), |
| cacheFields))); |
| |
| // Create the pivotCache entry in the workbook part |
| int cacheId = 1; |
| XDocument wb = document.WorkbookPart.GetXDocument(); |
| if (wb.Root.Element(S.pivotCaches) == null) |
| wb.Root.Add(new XElement(S.pivotCaches)); |
| else |
| { |
| if (wb.Root.Element(S.pivotCaches).Elements(S.pivotCache).Count() != 0) |
| cacheId = wb.Root.Element(S.pivotCaches).Elements(S.pivotCache).Max(n => Convert.ToInt32(n.Attribute(NoNamespace.cacheId).Value)) + 1; |
| } |
| wb.Root.Element(S.pivotCaches).Add(new XElement(S.pivotCache, |
| new XAttribute(NoNamespace.cacheId, cacheId), |
| new XAttribute(R.id, document.WorkbookPart.GetIdOfPart(cacheDef)))); |
| document.WorkbookPart.PutXDocument(); |
| |
| // Set the content for the PivotTablePart |
| pivotTable.PutXDocument(new XDocument(new XElement(S.pivotTableDefinition, new XAttribute("xmlns", S.s), |
| new XAttribute(NoNamespace.name, "PivotTable1"), new XAttribute(NoNamespace.cacheId, cacheId.ToString()), |
| new XAttribute(NoNamespace.dataCaption, "Values"), |
| new XElement(S.location, new XAttribute(NoNamespace._ref, "A3:C20"), |
| new XAttribute(NoNamespace.firstHeaderRow, "1"), new XAttribute(NoNamespace.firstDataRow, "1"), |
| new XAttribute(NoNamespace.firstDataCol, "0")), pivotFields))); |
| |
| return pivotTable; |
| } |
| |
| public enum PivotAxis { Row, Column, Page }; |
| public static void AddPivotAxis(SpreadsheetDocument document, WorksheetPart sheet, string fieldName, PivotAxis axis) |
| { |
| // Create indexed items in cache and definition |
| PivotTablePart pivotTablePart = sheet.GetPartsOfType<PivotTablePart>().First(); |
| PivotTableCacheDefinitionPart cacheDefPart = pivotTablePart.GetPartsOfType<PivotTableCacheDefinitionPart>().First(); |
| PivotTableCacheRecordsPart recordsPart = cacheDefPart.GetPartsOfType<PivotTableCacheRecordsPart>().First(); |
| XDocument cacheDef = cacheDefPart.GetXDocument(); |
| int index = Array.FindIndex(cacheDef.Descendants(S.cacheField).ToArray(), |
| z => z.Attribute(NoNamespace.name).Value == fieldName); |
| XDocument records = recordsPart.GetXDocument(); |
| List<XElement> values = new List<XElement>(); |
| foreach (XElement rec in records.Descendants(S.r)) |
| { |
| XElement val = rec.Elements().Skip(index).First(); |
| int x = Array.FindIndex(values.ToArray(), z => XElement.DeepEquals(z, val)); |
| if (x == -1) |
| { |
| values.Add(val); |
| x = values.Count() - 1; |
| } |
| val.ReplaceWith(new XElement(S.x, new XAttribute(NoNamespace.v, x))); |
| } |
| XElement sharedItems = cacheDef.Descendants(S.cacheField).Skip(index).First().Element(S.sharedItems); |
| sharedItems.Add(new XAttribute(NoNamespace.count, values.Count()), values); |
| recordsPart.PutXDocument(); |
| cacheDefPart.PutXDocument(); |
| |
| // Add axis definition to pivot table field |
| XDocument pivotTable = pivotTablePart.GetXDocument(); |
| XElement pivotField = pivotTable.Descendants(S.pivotField).Skip(index).First(); |
| XElement items = new XElement(S.items, new XAttribute(NoNamespace.count, values.Count() + 1), |
| values.OrderBy(z => z.Attribute(NoNamespace.v).Value).Select(z => new XElement(S.item, |
| new XAttribute(NoNamespace.x, Array.FindIndex(values.ToArray(), |
| a => a.Attribute(NoNamespace.v).Value == z.Attribute(NoNamespace.v).Value))))); |
| items.Add(new XElement(S.item, new XAttribute(NoNamespace.t, "default"))); |
| switch (axis) |
| { |
| case PivotAxis.Column: |
| pivotField.Add(new XAttribute(NoNamespace.axis, "axisCol"), items); |
| // Add to colFields |
| { |
| XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields); |
| if (fields == null) |
| { |
| fields = new XElement(S.colFields, new XAttribute(NoNamespace.count, 0)); |
| XElement rowFields = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields); |
| if (rowFields == null) |
| pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields); |
| else |
| rowFields.AddAfterSelf(fields); |
| } |
| fields.Add(new XElement(S.field, new XAttribute(NoNamespace.x, index))); |
| fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString(); |
| } |
| break; |
| case PivotAxis.Row: |
| pivotField.Add(new XAttribute(NoNamespace.axis, "axisRow"), items); |
| // Add to rowFields |
| { |
| XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields); |
| if (fields == null) |
| { |
| fields = new XElement(S.rowFields, new XAttribute(NoNamespace.count, 0)); |
| pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields); |
| } |
| fields.Add(new XElement(S.field, new XAttribute(NoNamespace.x, index))); |
| fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString(); |
| } |
| break; |
| case PivotAxis.Page: |
| pivotField.Add(new XAttribute(NoNamespace.axis, "axisPage"), items); |
| // Add to pageFields |
| { |
| XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.pageFields); |
| if (fields == null) |
| { |
| fields = new XElement(S.pageFields, new XAttribute(NoNamespace.count, 0)); |
| XElement prev = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields); |
| if (prev == null) |
| prev = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields); |
| if (prev == null) |
| pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields); |
| else |
| prev.AddAfterSelf(fields); |
| } |
| fields.Add(new XElement(S.pageField, new XAttribute(NoNamespace.fld, index))); |
| fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString(); |
| } |
| break; |
| } |
| pivotTablePart.PutXDocument(); |
| ForcePivotRefresh(cacheDefPart); |
| } |
| |
| public static void AddDataValueLabel(SpreadsheetDocument document, WorksheetPart sheet, PivotAxis axis) |
| { |
| PivotTablePart pivotTablePart = sheet.GetPartsOfType<PivotTablePart>().First(); |
| XDocument pivotTable = pivotTablePart.GetXDocument(); |
| switch (axis) |
| { |
| case PivotAxis.Column: |
| // Add to colFields |
| { |
| XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields); |
| if (fields == null) |
| { |
| fields = new XElement(S.colFields, new XAttribute(NoNamespace.count, 0)); |
| XElement rowFields = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields); |
| if (rowFields == null) |
| pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields); |
| else |
| rowFields.AddAfterSelf(fields); |
| } |
| fields.Add(new XElement(S.field, new XAttribute(NoNamespace.x, -2))); |
| fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString(); |
| } |
| break; |
| case PivotAxis.Row: |
| // Add to rowFields |
| { |
| XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields); |
| if (fields == null) |
| { |
| fields = new XElement(S.rowFields, new XAttribute(NoNamespace.count, 0)); |
| pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields); |
| } |
| fields.Add(new XElement(S.field, new XAttribute(NoNamespace.x, -2))); |
| fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString(); |
| } |
| break; |
| case PivotAxis.Page: |
| // Add to pageFields |
| { |
| XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.pageFields); |
| if (fields == null) |
| { |
| fields = new XElement(S.pageFields, new XAttribute(NoNamespace.count, 0)); |
| XElement prev = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields); |
| if (prev == null) |
| prev = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields); |
| if (prev == null) |
| pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields); |
| else |
| prev.AddAfterSelf(fields); |
| } |
| fields.Add(new XElement(S.pageField, new XAttribute(NoNamespace.fld, -2))); |
| fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString(); |
| } |
| break; |
| } |
| pivotTablePart.PutXDocument(); |
| PivotTableCacheDefinitionPart cacheDefPart = pivotTablePart.GetPartsOfType<PivotTableCacheDefinitionPart>().First(); |
| ForcePivotRefresh(cacheDefPart); |
| } |
| |
| public static void AddDataValue(SpreadsheetDocument document, WorksheetPart sheet, string fieldName) |
| { |
| PivotTablePart pivotTablePart = sheet.GetPartsOfType<PivotTablePart>().First(); |
| PivotTableCacheDefinitionPart cacheDefPart = pivotTablePart.GetPartsOfType<PivotTableCacheDefinitionPart>().First(); |
| XDocument cacheDef = cacheDefPart.GetXDocument(); |
| int index = Array.FindIndex(cacheDef.Descendants(S.cacheField).ToArray(), |
| z => z.Attribute(NoNamespace.name).Value == fieldName); |
| XDocument pivotTable = pivotTablePart.GetXDocument(); |
| XElement pivotField = pivotTable.Descendants(S.pivotField).Skip(index).First(); |
| pivotField.Add(new XAttribute(NoNamespace.dataField, "1")); |
| XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.dataFields); |
| if (fields == null) |
| { |
| fields = new XElement(S.dataFields, new XAttribute(NoNamespace.count, 0)); |
| XElement prev = pivotTable.Element(S.pivotTableDefinition).Element(S.pageFields); |
| if (prev == null) |
| prev = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields); |
| if (prev == null) |
| prev = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields); |
| if (prev == null) |
| prev = pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields); |
| prev.AddAfterSelf(fields); |
| } |
| fields.Add(new XElement(S.dataField, new XAttribute(NoNamespace.name, "Sum of " + fieldName), |
| new XAttribute(NoNamespace.fld, index), new XAttribute(NoNamespace.baseField, 0), |
| new XAttribute(NoNamespace.baseItem, 0))); |
| int count = fields.Elements(S.dataField).Count(); |
| fields.Attribute(NoNamespace.count).Value = count.ToString(); |
| if (count == 2) |
| { // Only when data field count goes from 1 to 2 do we add a special column to label the data fields |
| AddDataValueLabel(document, sheet, PivotAxis.Column); |
| } |
| pivotTablePart.PutXDocument(); |
| ForcePivotRefresh(cacheDefPart); |
| } |
| |
| private static void ForcePivotRefresh(PivotTableCacheDefinitionPart cacheDef) |
| { |
| XDocument doc = cacheDef.GetXDocument(); |
| XElement def = doc.Element(S.pivotCacheDefinition); |
| if (def.Attribute(NoNamespace.refreshOnLoad) == null) |
| def.Add(new XAttribute(NoNamespace.refreshOnLoad, 1)); |
| else |
| def.Attribute(NoNamespace.refreshOnLoad).Value = "1"; |
| cacheDef.PutXDocument(); |
| } |
| |
| public static void CheckNumberFormat(SpreadsheetDocument document, int fmtID, string formatCode) |
| { |
| XElement numFmt = new XElement(S.numFmt, new XAttribute(NoNamespace.numFmtId, fmtID.ToString()), |
| new XAttribute(NoNamespace.formatCode, formatCode)); |
| XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument(); |
| XElement numFmts = styles.Root.Element(S.numFmts); |
| if (numFmts == null) |
| { |
| styles.Root.Element(S.fonts).AddBeforeSelf(new XElement(S.numFmts, new XAttribute(NoNamespace.count, "0"))); |
| numFmts = styles.Root.Element(S.numFmts); |
| } |
| int index = Array.FindIndex(numFmts.Elements(S.numFmt).ToArray(), |
| z => XElement.DeepEquals(z, numFmt)); |
| if (index == -1) |
| { |
| numFmts.Add(numFmt); |
| numFmts.Attribute(NoNamespace.count).Value = numFmts.Elements(S.numFmt).Count().ToString(); |
| document.WorkbookPart.WorkbookStylesPart.PutXDocument(); |
| } |
| } |
| |
| public class ColorInfo |
| { |
| public enum ColorType { Theme, Indexed }; |
| |
| private bool Auto; |
| private string RGB; |
| private int Indexed; |
| private int Theme; |
| private double Tint; |
| |
| public ColorInfo() |
| { |
| Auto = true; |
| } |
| public ColorInfo(ColorType type, int value) |
| { |
| if (type == ColorType.Indexed) |
| Indexed = value; |
| else if (type == ColorType.Theme) |
| Theme = value; |
| } |
| public ColorInfo(int theme, double tint) |
| { |
| Theme = theme; |
| Tint = tint; |
| } |
| public ColorInfo(string rgb) |
| { |
| RGB = rgb; |
| } |
| |
| public XElement GetXElement(XName colorName) |
| { |
| XElement color = new XElement(colorName); |
| if (Auto) |
| color.Add(new XAttribute(NoNamespace.auto, "1")); |
| else if (RGB != null) |
| color.Add(new XAttribute(NoNamespace.rgb, RGB)); |
| else if (Indexed != 0) |
| color.Add(new XAttribute(NoNamespace.indexed, Indexed)); |
| else |
| color.Add(new XAttribute(NoNamespace.theme, Theme)); |
| if (Tint != 0) |
| color.Add(new XAttribute(NoNamespace.tint, Tint)); |
| return color; |
| } |
| } |
| |
| public class Font |
| { |
| public enum SchemeType { None, Major, Minor }; |
| |
| public bool Bold { get; set; } |
| public ColorInfo Color { get; set; } |
| public bool Condense { get; set; } |
| public bool Extend { get; set; } |
| public int Family { get; set; } |
| public bool Italic { get; set; } |
| public string Name { get; set; } |
| public bool Outline { get; set; } |
| public SchemeType Scheme { get; set; } |
| public bool Shadow { get; set; } |
| public bool StrikeThrough { get; set; } |
| public int Size { get; set; } |
| public bool Underline { get; set; } |
| |
| public XElement GetXElement() |
| { |
| XElement font = new XElement(S.font); |
| if (Bold) |
| font.Add(new XElement(S.b)); |
| if (Italic) |
| font.Add(new XElement(S.i)); |
| if (Underline) |
| font.Add(new XElement(S.u)); |
| if (StrikeThrough) |
| font.Add(new XElement(S.strike)); |
| if (Condense) |
| font.Add(new XElement(S.condense)); |
| if (Extend) |
| font.Add(new XElement(S.extend)); |
| if (Outline) |
| font.Add(new XElement(S.outline)); |
| if (Shadow) |
| font.Add(new XElement(S.shadow)); |
| if (Size != 0) |
| font.Add(new XElement(S.sz, new XAttribute(NoNamespace.val, Size.ToString()))); |
| if (Color != null) |
| font.Add(Color.GetXElement(S.color)); |
| if (Name != null) |
| font.Add(new XElement(S.name, new XAttribute(NoNamespace.val, Name))); |
| if (Family != 0) |
| font.Add(new XElement(S.family, new XAttribute(NoNamespace.val, Family.ToString()))); |
| switch (Scheme) |
| { |
| case SchemeType.Major: |
| font.Add(new XElement(S.scheme, new XAttribute(NoNamespace.val, "major"))); |
| break; |
| case SchemeType.Minor: |
| font.Add(new XElement(S.scheme, new XAttribute(NoNamespace.val, "minor"))); |
| break; |
| } |
| return font; |
| } |
| } |
| |
| public static int GetFontIndex(SpreadsheetDocument document, Font f) |
| { |
| XElement font = f.GetXElement(); |
| XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument(); |
| XElement fonts = styles.Root.Element(S.fonts); |
| int index = Array.FindIndex(fonts.Elements(S.font).ToArray(), |
| z => XElement.DeepEquals(z, font)); |
| if (index != -1) |
| return index; |
| fonts.Add(font); |
| fonts.Attribute(NoNamespace.count).Value = fonts.Elements(S.font).Count().ToString(); |
| document.WorkbookPart.WorkbookStylesPart.PutXDocument(); |
| return fonts.Elements(S.font).Count() - 1; |
| } |
| |
| public class PatternFill |
| { |
| public enum PatternType |
| { |
| None, Solid, DarkDown, DarkGray, DarkGrid, DarkHorizontal, DarkTrellis, DarkUp, DarkVertical, |
| Gray0625, Gray125, LightDown, LightGray, LightGrid, LightHorizontal, LightTrellis, LightUp, LightVertical, MediumGray |
| }; |
| |
| private PatternType Pattern; |
| private ColorInfo BgColor; |
| private ColorInfo FgColor; |
| |
| public PatternFill(PatternType pattern, ColorInfo bgColor, ColorInfo fgColor) |
| { |
| Pattern = pattern; |
| BgColor = bgColor; |
| FgColor = fgColor; |
| } |
| |
| public XElement GetXElement() |
| { |
| XElement pattern = new XElement(S.patternFill); |
| switch (Pattern) |
| { |
| case PatternType.DarkDown: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "darkDown")); |
| break; |
| case PatternType.DarkGray: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "darkGray")); |
| break; |
| case PatternType.DarkGrid: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "darkGrid")); |
| break; |
| case PatternType.DarkHorizontal: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "darkHorizontal")); |
| break; |
| case PatternType.DarkTrellis: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "darkTrellis")); |
| break; |
| case PatternType.DarkUp: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "darkUp")); |
| break; |
| case PatternType.DarkVertical: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "darkVertical")); |
| break; |
| case PatternType.Gray0625: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "gray0625")); |
| break; |
| case PatternType.Gray125: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "gray125")); |
| break; |
| case PatternType.LightDown: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "lightDown")); |
| break; |
| case PatternType.LightGray: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "lightGray")); |
| break; |
| case PatternType.LightGrid: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "lightGrid")); |
| break; |
| case PatternType.LightHorizontal: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "lightHorizontal")); |
| break; |
| case PatternType.LightTrellis: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "lightTrellis")); |
| break; |
| case PatternType.LightUp: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "lightUp")); |
| break; |
| case PatternType.LightVertical: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "lightVertical")); |
| break; |
| case PatternType.MediumGray: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "mediumGray")); |
| break; |
| case PatternType.None: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "none")); |
| break; |
| case PatternType.Solid: |
| pattern.Add(new XAttribute(NoNamespace.patternType, "solid")); |
| break; |
| } |
| if (FgColor != null) |
| pattern.Add(FgColor.GetXElement(S.fgColor)); |
| if (BgColor != null) |
| pattern.Add(BgColor.GetXElement(S.bgColor)); |
| return new XElement(S.fill, pattern); |
| } |
| } |
| |
| public class GradientStop |
| { |
| private double Position; |
| private ColorInfo Color; |
| |
| public GradientStop(double position, ColorInfo color) |
| { |
| Position = position; |
| Color = color; |
| } |
| |
| public XElement GetXElement() |
| { |
| return new XElement(S.stop, new XAttribute(NoNamespace.position, Position), Color.GetXElement(S.color)); |
| } |
| } |
| |
| public class GradientFill |
| { |
| private bool PathGradient; |
| private int LinearDegree; |
| private double PathTop; |
| private double PathLeft; |
| private double PathBottom; |
| private double PathRight; |
| private List<GradientStop> Stops; |
| |
| public GradientFill(int degree) |
| { |
| PathGradient = false; |
| LinearDegree = degree; |
| Stops = new List<GradientStop>(); |
| } |
| |
| public GradientFill(double top, double left, double bottom, double right) |
| { |
| PathGradient = true; |
| PathTop = top; |
| PathLeft = left; |
| PathBottom = bottom; |
| PathRight = right; |
| Stops = new List<GradientStop>(); |
| } |
| |
| public void AddStop(GradientStop stop) |
| { |
| Stops.Add(stop); |
| } |
| |
| public XElement GetXElement() |
| { |
| XElement gradient = new XElement(S.gradientFill); |
| if (PathGradient) |
| { |
| gradient.Add(new XAttribute(NoNamespace.type, "path"), |
| new XAttribute(NoNamespace.left, PathLeft.ToString()), new XAttribute(NoNamespace.right, PathRight.ToString()), |
| new XAttribute(NoNamespace.top, PathTop.ToString()), new XAttribute(NoNamespace.bottom, PathBottom.ToString())); |
| } |
| else |
| { |
| gradient.Add(new XAttribute(NoNamespace.degree, LinearDegree.ToString())); |
| } |
| foreach (GradientStop stop in Stops) |
| gradient.Add(stop.GetXElement()); |
| return new XElement(S.fill, gradient); |
| } |
| } |
| |
| public static int GetFillIndex(SpreadsheetDocument document, PatternFill patternFill) |
| { |
| return GetFillIndex(document, patternFill.GetXElement()); |
| } |
| |
| public static int GetFillIndex(SpreadsheetDocument document, GradientFill gradientFill) |
| { |
| return GetFillIndex(document, gradientFill.GetXElement()); |
| } |
| |
| private static int GetFillIndex(SpreadsheetDocument document, XElement fill) |
| { |
| XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument(); |
| XElement fills = styles.Root.Element(S.fills); |
| int index = Array.FindIndex(fills.Elements(S.fill).ToArray(), |
| z => XElement.DeepEquals(z, fill)); |
| if (index != -1) |
| return index; |
| fills.Add(fill); |
| fills.Attribute(NoNamespace.count).Value = fills.Elements(S.fill).Count().ToString(); |
| document.WorkbookPart.WorkbookStylesPart.PutXDocument(); |
| return fills.Elements(S.fill).Count() - 1; |
| } |
| |
| public class BorderLine |
| { |
| public enum LineStyle |
| { |
| None, DashDot, DashDotDot, Dashed, Dotted, Double, Hair, |
| Medium, MediumDashDot, MediumDashDotDot, MediumDashed, SlantDashDot, Thick, Thin |
| }; |
| private LineStyle Style; |
| private ColorInfo Color; |
| |
| public BorderLine(LineStyle style, ColorInfo color) |
| { |
| Style = style; |
| Color = color; |
| } |
| |
| public XElement GetXElement(XName name) |
| { |
| XElement line = new XElement(name); |
| switch (Style) |
| { |
| case LineStyle.DashDot: |
| line.Add(new XAttribute(NoNamespace.style, "dashDot")); |
| break; |
| case LineStyle.DashDotDot: |
| line.Add(new XAttribute(NoNamespace.style, "dashDotDot")); |
| break; |
| case LineStyle.Dashed: |
| line.Add(new XAttribute(NoNamespace.style, "dashed")); |
| break; |
| case LineStyle.Dotted: |
| line.Add(new XAttribute(NoNamespace.style, "dotted")); |
| break; |
| case LineStyle.Double: |
| line.Add(new XAttribute(NoNamespace.style, "double")); |
| break; |
| case LineStyle.Hair: |
| line.Add(new XAttribute(NoNamespace.style, "hair")); |
| break; |
| case LineStyle.Medium: |
| line.Add(new XAttribute(NoNamespace.style, "medium")); |
| break; |
| case LineStyle.MediumDashDot: |
| line.Add(new XAttribute(NoNamespace.style, "mediumDashDot")); |
| break; |
| case LineStyle.MediumDashDotDot: |
| line.Add(new XAttribute(NoNamespace.style, "mediumDashDotDot")); |
| break; |
| case LineStyle.MediumDashed: |
| line.Add(new XAttribute(NoNamespace.style, "mediumDashed")); |
| break; |
| case LineStyle.SlantDashDot: |
| line.Add(new XAttribute(NoNamespace.style, "slantDashDot")); |
| break; |
| case LineStyle.Thick: |
| line.Add(new XAttribute(NoNamespace.style, "thick")); |
| break; |
| case LineStyle.Thin: |
| line.Add(new XAttribute(NoNamespace.style, "thin")); |
| break; |
| } |
| line.Add(Color.GetXElement(S.color)); |
| return line; |
| } |
| } |
| |
| public class Border |
| { |
| public BorderLine Top { get; set; } |
| public BorderLine Bottom { get; set; } |
| public BorderLine Left { get; set; } |
| public BorderLine Right { get; set; } |
| public BorderLine Horizontal { get; set; } |
| public BorderLine Vertical { get; set; } |
| public BorderLine Diagonal { get; set; } |
| public bool DiagonalDown { get; set; } |
| public bool DiagonalUp { get; set; } |
| public bool Outline { get; set; } |
| |
| public XElement GetXElement() |
| { |
| XElement border = new XElement(S.border); |
| if (DiagonalDown) |
| border.Add(new XAttribute(NoNamespace.diagonalDown, "1")); |
| if (DiagonalUp) |
| border.Add(new XAttribute(NoNamespace.diagonalUp, "1")); |
| if (Outline) |
| border.Add(new XAttribute(NoNamespace.outline, "1")); |
| if (Left == null) |
| border.Add(new XElement(S.left)); |
| else |
| border.Add(Left.GetXElement(S.left)); |
| if (Right == null) |
| border.Add(new XElement(S.right)); |
| else |
| border.Add(Right.GetXElement(S.right)); |
| if (Top == null) |
| border.Add(new XElement(S.top)); |
| else |
| border.Add(Top.GetXElement(S.top)); |
| if (Bottom == null) |
| border.Add(new XElement(S.bottom)); |
| else |
| border.Add(Bottom.GetXElement(S.bottom)); |
| if (Diagonal == null) |
| border.Add(new XElement(S.diagonal)); |
| else |
| border.Add(Diagonal.GetXElement(S.diagonal)); |
| if (Horizontal != null) |
| border.Add(Horizontal.GetXElement(S.horizontal)); |
| if (Vertical != null) |
| border.Add(Vertical.GetXElement(S.vertical)); |
| return border; |
| } |
| } |
| |
| public static int GetBorderIndex(SpreadsheetDocument document, Border b) |
| { |
| XElement border = b.GetXElement(); |
| XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument(); |
| XElement borders = styles.Root.Element(S.borders); |
| int index = Array.FindIndex(borders.Elements(S.border).ToArray(), |
| z => XElement.DeepEquals(z, border)); |
| if (index != -1) |
| return index; |
| borders.Add(border); |
| borders.Attribute(NoNamespace.count).Value = borders.Elements(S.border).Count().ToString(); |
| document.WorkbookPart.WorkbookStylesPart.PutXDocument(); |
| return borders.Elements(S.border).Count() - 1; |
| } |
| |
| public static int GetStyleIndex(SpreadsheetDocument document, string styleName) |
| { |
| XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument(); |
| string xfId = styles.Root.Element(S.cellStyles).Elements(S.cellStyle) |
| .Where(t => t.Attribute(NoNamespace.name).Value == styleName) |
| .FirstOrDefault().Attribute(NoNamespace.xfId).Value; |
| XElement cellXfs = styles.Root.Element(S.cellXfs); |
| int index = Array.FindIndex(cellXfs.Elements(S.xf).ToArray(), |
| z => z.Attribute(NoNamespace.xfId).Value == xfId); |
| if (index != -1) |
| return index; |
| XElement cellStyleXf = styles.Root.Element(S.cellStyleXfs).Elements(S.xf).ToArray()[Convert.ToInt32(xfId)]; |
| if (cellStyleXf != null) |
| { // Create new xf element under cellXfs |
| cellXfs.Add(new XElement(S.xf, new XAttribute(NoNamespace.numFmtId, cellStyleXf.Attribute(NoNamespace.numFmtId).Value), |
| new XAttribute(NoNamespace.fontId, cellStyleXf.Attribute(NoNamespace.fontId).Value), |
| new XAttribute(NoNamespace.fillId, cellStyleXf.Attribute(NoNamespace.fillId).Value), |
| new XAttribute(NoNamespace.borderId, cellStyleXf.Attribute(NoNamespace.borderId).Value), |
| new XAttribute(NoNamespace.xfId, xfId))); |
| cellXfs.Attribute(NoNamespace.count).Value = cellXfs.Elements(S.xf).Count().ToString(); |
| document.WorkbookPart.WorkbookStylesPart.PutXDocument(); |
| return cellXfs.Elements(S.xf).Count() - 1; |
| } |
| |
| return 0; |
| } |
| |
| public class CellAlignment |
| { |
| public enum Horizontal { General, Center, CenterContinuous, Distributed, Fill, Justify, Left, Right }; |
| public enum Vertical { Bottom, Center, Distributed, Justify, Top }; |
| |
| public Horizontal HorizontalAlignment { get; set; } |
| public int Indent { get; set; } |
| public bool JustifyLastLine { get; set; } |
| public int ReadingOrder { get; set; } |
| public bool ShrinkToFit { get; set; } |
| public int TextRotation { get; set; } |
| public Vertical VerticalAlignment { get; set; } |
| public bool WrapText { get; set; } |
| |
| public CellAlignment() |
| { |
| HorizontalAlignment = Horizontal.General; |
| Indent = 0; |
| JustifyLastLine = false; |
| ReadingOrder = 0; |
| ShrinkToFit = false; |
| TextRotation = 0; |
| VerticalAlignment = Vertical.Bottom; |
| WrapText = false; |
| } |
| |
| public XElement GetXElement() |
| { |
| XElement align = new XElement(S.alignment); |
| switch (HorizontalAlignment) |
| { |
| case Horizontal.Center: |
| align.Add(new XAttribute(NoNamespace.horizontal, "center")); |
| break; |
| case Horizontal.CenterContinuous: |
| align.Add(new XAttribute(NoNamespace.horizontal, "centerContinuous")); |
| break; |
| case Horizontal.Distributed: |
| align.Add(new XAttribute(NoNamespace.horizontal, "distributed")); |
| break; |
| case Horizontal.Fill: |
| align.Add(new XAttribute(NoNamespace.horizontal, "fill")); |
| break; |
| case Horizontal.Justify: |
| align.Add(new XAttribute(NoNamespace.horizontal, "justify")); |
| break; |
| case Horizontal.Left: |
| align.Add(new XAttribute(NoNamespace.horizontal, "left")); |
| break; |
| case Horizontal.Right: |
| align.Add(new XAttribute(NoNamespace.horizontal, "right")); |
| break; |
| } |
| if (Indent != 0) |
| align.Add(new XAttribute(NoNamespace.indent, Indent)); |
| if (JustifyLastLine) |
| align.Add(new XAttribute(NoNamespace.justifyLastLine, true)); |
| if (ReadingOrder != 0) |
| align.Add(new XAttribute(NoNamespace.readingOrder, ReadingOrder)); |
| if (ShrinkToFit) |
| align.Add(new XAttribute(NoNamespace.shrinkToFit, true)); |
| if (TextRotation != 0) |
| align.Add(new XAttribute(NoNamespace.textRotation, TextRotation)); |
| switch (VerticalAlignment) |
| { |
| case Vertical.Center: |
| align.Add(new XAttribute(NoNamespace.vertical, "center")); |
| break; |
| case Vertical.Distributed: |
| align.Add(new XAttribute(NoNamespace.vertical, "distributed")); |
| break; |
| case Vertical.Justify: |
| align.Add(new XAttribute(NoNamespace.vertical, "justify")); |
| break; |
| case Vertical.Top: |
| align.Add(new XAttribute(NoNamespace.vertical, "top")); |
| break; |
| } |
| if (WrapText) |
| align.Add(new XAttribute(NoNamespace.wrapText, true)); |
| return align; |
| } |
| } |
| |
| public static int GetStyleIndex(SpreadsheetDocument document, int numFmt, int font, int fill, int border, CellAlignment alignment, bool hidden, bool locked) |
| { |
| XElement xf = new XElement(S.xf, new XAttribute(NoNamespace.numFmtId, numFmt), |
| new XAttribute(NoNamespace.fontId, font), new XAttribute(NoNamespace.fillId, fill), |
| new XAttribute(NoNamespace.borderId, border), new XAttribute(NoNamespace.xfId, 0), |
| new XAttribute(NoNamespace.applyNumberFormat, (numFmt == 0) ? 0 : 1), |
| new XAttribute(NoNamespace.applyFont, (font == 0) ? 0 : 1), |
| new XAttribute(NoNamespace.applyFill, (fill == 0) ? 0 : 1), |
| new XAttribute(NoNamespace.applyBorder, (border == 0) ? 0 : 1)); |
| if (alignment != null) |
| { |
| xf.Add(new XAttribute(NoNamespace.applyAlignment, "1")); |
| xf.Add(alignment.GetXElement()); |
| } |
| else |
| xf.Add(new XAttribute(NoNamespace.applyAlignment, "0")); |
| if (hidden || locked) |
| { |
| XElement prot = new XElement(S.protection); |
| if (hidden) |
| prot.Add(new XAttribute(NoNamespace.hidden, true)); |
| if (locked) |
| prot.Add(new XAttribute(NoNamespace.locked, true)); |
| xf.Add(prot); |
| xf.Add(new XAttribute(NoNamespace.applyProtection, "1")); |
| } |
| else |
| xf.Add(new XAttribute(NoNamespace.applyProtection, "0")); |
| |
| XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument(); |
| XElement cellXfs = styles.Root.Element(S.cellXfs); |
| int index = Array.FindIndex(cellXfs.Elements(S.xf).ToArray(), |
| z => XElement.DeepEquals(z, xf)); |
| if (index != -1) |
| return index; |
| cellXfs.Add(xf); |
| cellXfs.Attribute(NoNamespace.count).Value = cellXfs.Elements(S.xf).Count().ToString(); |
| document.WorkbookPart.WorkbookStylesPart.PutXDocument(); |
| return cellXfs.Elements(S.xf).Count() - 1; |
| } |
| |
| public static void CreateDefaultStyles(SpreadsheetDocument document) |
| { |
| // Create the style part |
| WorkbookStylesPart stylesPart = document.WorkbookPart.AddNewPart<WorkbookStylesPart>(); |
| stylesPart.PutXDocument(new XDocument(XElement.Parse( |
| @"<?xml version='1.0' encoding='UTF-8' standalone='yes'?> |
| <styleSheet xmlns='http://schemas.openxmlformats.org/spreadsheetml/2006/main'> |
| <fonts count='18'> |
| <font> |
| <sz val='11'/> |
| <color theme='1'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <sz val='11'/> |
| <color theme='1'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <b/> |
| <sz val='18'/> |
| <color theme='3'/> |
| <name val='Cambria'/> |
| <family val='2'/> |
| <scheme val='major'/> |
| </font> |
| <font> |
| <b/> |
| <sz val='15'/> |
| <color theme='3'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <b/> |
| <sz val='13'/> |
| <color theme='3'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <b/> |
| <sz val='11'/> |
| <color theme='3'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <sz val='11'/> |
| <color rgb='FF006100'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <sz val='11'/> |
| <color rgb='FF9C0006'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <sz val='11'/> |
| <color rgb='FF9C6500'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <sz val='11'/> |
| <color rgb='FF3F3F76'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <b/> |
| <sz val='11'/> |
| <color rgb='FF3F3F3F'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <b/> |
| <sz val='11'/> |
| <color rgb='FFFA7D00'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <sz val='11'/> |
| <color rgb='FFFA7D00'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <b/> |
| <sz val='11'/> |
| <color theme='0'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <sz val='11'/> |
| <color rgb='FFFF0000'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <i/> |
| <sz val='11'/> |
| <color rgb='FF7F7F7F'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <b/> |
| <sz val='11'/> |
| <color theme='1'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| <font> |
| <sz val='11'/> |
| <color theme='0'/> |
| <name val='Calibri'/> |
| <family val='2'/> |
| <scheme val='minor'/> |
| </font> |
| </fonts> |
| <fills count='33'> |
| <fill> |
| <patternFill patternType='none'/> |
| </fill> |
| <fill> |
| <patternFill patternType='gray125'/> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor rgb='FFC6EFCE'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor rgb='FFFFC7CE'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor rgb='FFFFEB9C'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor rgb='FFFFCC99'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor rgb='FFF2F2F2'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor rgb='FFA5A5A5'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor rgb='FFFFFFCC'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='4'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='4' tint='0.79998168889431442'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='4' tint='0.59999389629810485'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='4' tint='0.39997558519241921'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='5'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='5' tint='0.79998168889431442'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='5' tint='0.59999389629810485'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='5' tint='0.39997558519241921'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='6'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='6' tint='0.79998168889431442'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='6' tint='0.59999389629810485'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='6' tint='0.39997558519241921'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='7'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='7' tint='0.79998168889431442'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='7' tint='0.59999389629810485'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='7' tint='0.39997558519241921'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='8'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='8' tint='0.79998168889431442'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='8' tint='0.59999389629810485'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='8' tint='0.39997558519241921'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='9'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='9' tint='0.79998168889431442'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='9' tint='0.59999389629810485'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| <fill> |
| <patternFill patternType='solid'> |
| <fgColor theme='9' tint='0.39997558519241921'/> |
| <bgColor indexed='65'/> |
| </patternFill> |
| </fill> |
| </fills> |
| <borders count='10'> |
| <border> |
| <left/> |
| <right/> |
| <top/> |
| <bottom/> |
| <diagonal/> |
| </border> |
| <border> |
| <left/> |
| <right/> |
| <top/> |
| <bottom style='thick'> |
| <color theme='4'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| <border> |
| <left/> |
| <right/> |
| <top/> |
| <bottom style='thick'> |
| <color theme='4' tint='0.499984740745262'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| <border> |
| <left/> |
| <right/> |
| <top/> |
| <bottom style='medium'> |
| <color theme='4' tint='0.39997558519241921'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| <border> |
| <left style='thin'> |
| <color rgb='FF7F7F7F'/> |
| </left> |
| <right style='thin'> |
| <color rgb='FF7F7F7F'/> |
| </right> |
| <top style='thin'> |
| <color rgb='FF7F7F7F'/> |
| </top> |
| <bottom style='thin'> |
| <color rgb='FF7F7F7F'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| <border> |
| <left style='thin'> |
| <color rgb='FF3F3F3F'/> |
| </left> |
| <right style='thin'> |
| <color rgb='FF3F3F3F'/> |
| </right> |
| <top style='thin'> |
| <color rgb='FF3F3F3F'/> |
| </top> |
| <bottom style='thin'> |
| <color rgb='FF3F3F3F'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| <border> |
| <left/> |
| <right/> |
| <top/> |
| <bottom style='double'> |
| <color rgb='FFFF8001'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| <border> |
| <left style='double'> |
| <color rgb='FF3F3F3F'/> |
| </left> |
| <right style='double'> |
| <color rgb='FF3F3F3F'/> |
| </right> |
| <top style='double'> |
| <color rgb='FF3F3F3F'/> |
| </top> |
| <bottom style='double'> |
| <color rgb='FF3F3F3F'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| <border> |
| <left style='thin'> |
| <color rgb='FFB2B2B2'/> |
| </left> |
| <right style='thin'> |
| <color rgb='FFB2B2B2'/> |
| </right> |
| <top style='thin'> |
| <color rgb='FFB2B2B2'/> |
| </top> |
| <bottom style='thin'> |
| <color rgb='FFB2B2B2'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| <border> |
| <left/> |
| <right/> |
| <top style='thin'> |
| <color theme='4'/> |
| </top> |
| <bottom style='double'> |
| <color theme='4'/> |
| </bottom> |
| <diagonal/> |
| </border> |
| </borders> |
| <cellStyleXfs count='42'> |
| <xf numFmtId='0' fontId='0' fillId='0' borderId='0'/> |
| <xf numFmtId='0' fontId='2' fillId='0' borderId='0' applyNumberFormat='0' applyFill='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='3' fillId='0' borderId='1' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='4' fillId='0' borderId='2' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='5' fillId='0' borderId='3' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='5' fillId='0' borderId='0' applyNumberFormat='0' applyFill='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='6' fillId='2' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='7' fillId='3' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='8' fillId='4' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='9' fillId='5' borderId='4' applyNumberFormat='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='10' fillId='6' borderId='5' applyNumberFormat='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='11' fillId='6' borderId='4' applyNumberFormat='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='12' fillId='0' borderId='6' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='13' fillId='7' borderId='7' applyNumberFormat='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='14' fillId='0' borderId='0' applyNumberFormat='0' applyFill='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='8' borderId='8' applyNumberFormat='0' applyFont='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='15' fillId='0' borderId='0' applyNumberFormat='0' applyFill='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='16' fillId='0' borderId='9' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='9' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='10' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='11' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='12' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='13' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='14' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='15' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='16' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='17' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='18' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='19' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='20' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='21' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='22' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='23' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='24' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='25' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='26' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='27' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='28' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='29' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='30' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='1' fillId='31' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| <xf numFmtId='0' fontId='17' fillId='32' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/> |
| </cellStyleXfs> |
| <cellXfs count='1'> |
| <xf numFmtId='0' fontId='0' fillId='0' borderId='0' xfId='0'/> |
| </cellXfs> |
| <cellStyles count='42'> |
| <cellStyle name='20% - Accent1' xfId='19' builtinId='30' customBuiltin='1'/> |
| <cellStyle name='20% - Accent2' xfId='23' builtinId='34' customBuiltin='1'/> |
| <cellStyle name='20% - Accent3' xfId='27' builtinId='38' customBuiltin='1'/> |
| <cellStyle name='20% - Accent4' xfId='31' builtinId='42' customBuiltin='1'/> |
| <cellStyle name='20% - Accent5' xfId='35' builtinId='46' customBuiltin='1'/> |
| <cellStyle name='20% - Accent6' xfId='39' builtinId='50' customBuiltin='1'/> |
| <cellStyle name='40% - Accent1' xfId='20' builtinId='31' customBuiltin='1'/> |
| <cellStyle name='40% - Accent2' xfId='24' builtinId='35' customBuiltin='1'/> |
| <cellStyle name='40% - Accent3' xfId='28' builtinId='39' customBuiltin='1'/> |
| <cellStyle name='40% - Accent4' xfId='32' builtinId='43' customBuiltin='1'/> |
| <cellStyle name='40% - Accent5' xfId='36' builtinId='47' customBuiltin='1'/> |
| <cellStyle name='40% - Accent6' xfId='40' builtinId='51' customBuiltin='1'/> |
| <cellStyle name='60% - Accent1' xfId='21' builtinId='32' customBuiltin='1'/> |
| <cellStyle name='60% - Accent2' xfId='25' builtinId='36' customBuiltin='1'/> |
| <cellStyle name='60% - Accent3' xfId='29' builtinId='40' customBuiltin='1'/> |
| <cellStyle name='60% - Accent4' xfId='33' builtinId='44' customBuiltin='1'/> |
| <cellStyle name='60% - Accent5' xfId='37' builtinId='48' customBuiltin='1'/> |
| <cellStyle name='60% - Accent6' xfId='41' builtinId='52' customBuiltin='1'/> |
| <cellStyle name='Accent1' xfId='18' builtinId='29' customBuiltin='1'/> |
| <cellStyle name='Accent2' xfId='22' builtinId='33' customBuiltin='1'/> |
| <cellStyle name='Accent3' xfId='26' builtinId='37' customBuiltin='1'/> |
| <cellStyle name='Accent4' xfId='30' builtinId='41' customBuiltin='1'/> |
| <cellStyle name='Accent5' xfId='34' builtinId='45' customBuiltin='1'/> |
| <cellStyle name='Accent6' xfId='38' builtinId='49' customBuiltin='1'/> |
| <cellStyle name='Bad' xfId='7' builtinId='27' customBuiltin='1'/> |
| <cellStyle name='Calculation' xfId='11' builtinId='22' customBuiltin='1'/> |
| <cellStyle name='Check Cell' xfId='13' builtinId='23' customBuiltin='1'/> |
| <cellStyle name='Explanatory Text' xfId='16' builtinId='53' customBuiltin='1'/> |
| <cellStyle name='Good' xfId='6' builtinId='26' customBuiltin='1'/> |
| <cellStyle name='Heading 1' xfId='2' builtinId='16' customBuiltin='1'/> |
| <cellStyle name='Heading 2' xfId='3' builtinId='17' customBuiltin='1'/> |
| <cellStyle name='Heading 3' xfId='4' builtinId='18' customBuiltin='1'/> |
| <cellStyle name='Heading 4' xfId='5' builtinId='19' customBuiltin='1'/> |
| <cellStyle name='Input' xfId='9' builtinId='20' customBuiltin='1'/> |
| <cellStyle name='Linked Cell' xfId='12' builtinId='24' customBuiltin='1'/> |
| <cellStyle name='Neutral' xfId='8' builtinId='28' customBuiltin='1'/> |
| <cellStyle name='Normal' xfId='0' builtinId='0'/> |
| <cellStyle name='Note' xfId='15' builtinId='10' customBuiltin='1'/> |
| <cellStyle name='Output' xfId='10' builtinId='21' customBuiltin='1'/> |
| <cellStyle name='Title' xfId='1' builtinId='15' customBuiltin='1'/> |
| <cellStyle name='Total' xfId='17' builtinId='25' customBuiltin='1'/> |
| <cellStyle name='Warning Text' xfId='14' builtinId='11' customBuiltin='1'/> |
| </cellStyles> |
| <dxfs count='0'/> |
| <tableStyles count='0' defaultTableStyle='TableStyleMedium9' defaultPivotStyle='PivotStyleLight16'/> |
| </styleSheet>"))); |
| } |
| |
| /// <summary> |
| /// Creates a worksheet document and inserts data into it |
| /// </summary> |
| /// <param name="headerList">List of values that will act as the header</param> |
| /// <param name="valueTable">Values for worksheet content</param> |
| /// <param name="headerRow">Header row</param> |
| /// <returns></returns> |
| internal static WorksheetPart Create(SpreadsheetDocument document, List<string> headerList, string[][] valueTable, int headerRow) |
| { |
| XDocument xDocument = CreateEmptyWorksheet(); |
| |
| for (int i = 0; i < headerList.Count; i++) |
| { |
| AddValue(xDocument, headerRow, i + 1, headerList[i]); |
| } |
| int rows = valueTable.GetLength(0); |
| int cols = valueTable[0].GetLength(0); |
| |
| for (int i = 0; i < rows; i++) |
| { |
| for (int j = 0; j < cols; j++) |
| { |
| AddValue(xDocument, i + headerRow + 1, j + 1, valueTable[i][j]); |
| } |
| } |
| WorksheetPart part = Add(document, xDocument); |
| return part; |
| } |
| |
| /// <summary> |
| /// Creates element structure needed to describe an empty worksheet |
| /// </summary> |
| /// <returns>Document with contents for an empty worksheet</returns> |
| private static XDocument CreateEmptyWorksheet() |
| { |
| XDocument document = |
| new XDocument( |
| new XElement(ns + "worksheet", |
| new XAttribute("xmlns", ns), |
| new XAttribute(XNamespace.Xmlns + "r", relationshipsns), |
| new XElement(ns + "sheetData") |
| ) |
| ); |
| return document; |
| } |
| |
| /// <summary> |
| /// Adds a value to a cell inside a worksheet document |
| /// </summary> |
| /// <param name="worksheet">document to add values</param> |
| /// <param name="row">Row</param> |
| /// <param name="column">Column</param> |
| /// <param name="value">Value to add</param> |
| private static void AddValue(XDocument worksheet, int row, int column, string value) |
| { |
| //Set the cell reference |
| string cellReference = GetColumnId(column) + row.ToString(); |
| double numericValue; |
| //Determining if value for cell is text or numeric |
| bool valueIsNumeric = double.TryParse(value, out numericValue); |
| |
| //Creating the new cell element (markup) |
| XElement newCellXElement = valueIsNumeric ? |
| new XElement(ns + "c", |
| new XAttribute("r", cellReference), |
| new XElement(ns + "v", numericValue) |
| ) |
| : |
| new XElement(ns + "c", |
| new XAttribute("r", cellReference), |
| new XAttribute("t", "inlineStr"), |
| new XElement(ns + "is", |
| new XElement(ns + "t", value) |
| ) |
| ); |
| |
| // Find the row containing the cell to add the value to |
| XName rowName = "r"; |
| XElement rowElement = |
| worksheet.Root |
| .Element(ns + "sheetData") |
| .Elements(ns + "row") |
| .Where( |
| t => t.Attribute(rowName).Value == row.ToString() |
| ) |
| .FirstOrDefault(); |
| |
| if (rowElement == null) |
| { |
| //row element does not exist |
| //create a new one |
| rowElement = CreateEmptyRow(row); |
| |
| //row elements must appear in order inside sheetData element |
| if (worksheet.Root |
| .Element(ns + "sheetData").HasElements) |
| { //if there are more rows already defined at sheetData element |
| //find the row with the inmediate higher index for the row containing the cell to set the value to |
| XElement rowAfterElement = FindRowAfter(worksheet, row); |
| //if there is a row with an inmediate higher index already defined at sheetData |
| if (rowAfterElement != null) |
| { |
| //add the new row before the row with an inmediate higher index |
| rowAfterElement.AddBeforeSelf(rowElement); |
| } |
| else |
| { //this row is going to be the one with the highest index (add it as the last element for sheetData) |
| worksheet.Root.Element(ns + "sheetData").Elements(ns + "row").Last().AddAfterSelf(rowElement); |
| } |
| } |
| else |
| { //there are no other rows already defined at sheetData |
| //Add a new row elemento to sheetData |
| worksheet |
| .Root |
| .Element(ns + "sheetData") |
| .Add( |
| rowElement //= CreateEmptyRow(row) |
| ); |
| } |
| |
| //Add the new cell to the row Element |
| rowElement.Add(newCellXElement); |
| } |
| else |
| { |
| //row containing the cell to set the value to is already defined at sheetData |
| //look if cell already exist at that row |
| XElement currentCellXElement = rowElement |
| .Elements(ns + "c") |
| .Where( |
| t => t.Attribute("r").Value == cellReference |
| ).FirstOrDefault(); |
| |
| if (currentCellXElement == null) |
| { //cell element does not exist at row indicated as parameter |
| //find the inmediate right column for the cell to set the value to |
| XElement columnAfterXElement = FindColumAfter(worksheet, row, column); |
| if (columnAfterXElement != null) |
| { |
| //Insert the new cell before the inmediate right column |
| columnAfterXElement.AddBeforeSelf(newCellXElement); |
| } |
| else |
| { //There is no inmediate right cell |
| //Add the new cell as the last element for the row |
| rowElement.Add(newCellXElement); |
| } |
| } |
| else |
| { |
| //cell alreay exist |
| //replace the current cell with that with the new value |
| currentCellXElement.ReplaceWith(newCellXElement); |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Adds a given worksheet to the document |
| /// </summary> |
| /// <param name="worksheet">Worksheet document to add</param> |
| /// <returns>Worksheet part just added</returns> |
| public static WorksheetPart Add(SpreadsheetDocument doc, XDocument worksheet) |
| { |
| // Associates base content to a new worksheet part |
| WorkbookPart workbook = doc.WorkbookPart; |
| WorksheetPart worksheetPart = workbook.AddNewPart<WorksheetPart>(); |
| worksheetPart.PutXDocument(worksheet); |
| |
| // Associates the worksheet part to the workbook part |
| XDocument document = doc.WorkbookPart.GetXDocument(); |
| int sheetId = |
| document.Root |
| .Element(ns + "sheets") |
| .Elements(ns + "sheet") |
| .Count() + 1; |
| |
| int worksheetCount = |
| document.Root |
| .Element(ns + "sheets") |
| .Elements(ns + "sheet") |
| .Where( |
| t => |
| t.Attribute("name").Value.StartsWith("sheet", StringComparison.OrdinalIgnoreCase) |
| ) |
| .Count() + 1; |
| |
| // Adds content to workbook document to reference worksheet document |
| document.Root |
| .Element(ns + "sheets") |
| .Add( |
| new XElement(ns + "sheet", |
| new XAttribute("name", string.Format("sheet{0}", worksheetCount)), |
| new XAttribute("sheetId", sheetId), |
| new XAttribute(relationshipsns + "id", workbook.GetIdOfPart(worksheetPart)) |
| ) |
| ); |
| doc.WorkbookPart.PutXDocument(); |
| return worksheetPart; |
| } |
| } |
| } |