12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091 |
- // Copyright (c) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Drawing;
- using System.Globalization;
- using System.Linq;
- using System.Text;
- using System.Xml.Linq;
- using DocumentFormat.OpenXml.Packaging;
- using System.IO;
- using OpenXmlPowerTools;
- namespace OpenXmlPowerTools
- {
- public class SmlDataRetriever
- {
- public static XElement RetrieveSheet(SmlDocument smlDoc, string sheetName)
- {
- using (MemoryStream ms = new MemoryStream())
- {
- ms.Write(smlDoc.DocumentByteArray, 0, smlDoc.DocumentByteArray.Length);
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(ms, false))
- {
- return RetrieveSheet(sDoc, sheetName);
- }
- }
- }
- public static XElement RetrieveSheet(string fileName, string sheetName)
- {
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(fileName, false))
- {
- return RetrieveSheet(sDoc, sheetName);
- }
- }
- public static XElement RetrieveSheet(SpreadsheetDocument sDoc, string sheetName)
- {
- var wbXdoc = sDoc.WorkbookPart.GetXDocument();
- var sheet = wbXdoc
- .Root
- .Elements(S.sheets)
- .Elements(S.sheet)
- .FirstOrDefault(s => (string)s.Attribute("name") == sheetName);
- if (sheet == null)
- throw new ArgumentException("Invalid sheet name passed to RetrieveSheet", "sheetName");
- var range = "A1:XFD1048576";
- int leftColumn, topRow, rightColumn, bottomRow;
- XlsxTables.ParseRange(range, out leftColumn, out topRow, out rightColumn, out bottomRow);
- return RetrieveRange(sDoc, sheetName, leftColumn, topRow, rightColumn, bottomRow);
- }
- public static XElement RetrieveRange(SmlDocument smlDoc, string sheetName, string range)
- {
- using (MemoryStream ms = new MemoryStream())
- {
- ms.Write(smlDoc.DocumentByteArray, 0, smlDoc.DocumentByteArray.Length);
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(ms, false))
- {
- return RetrieveRange(sDoc, sheetName, range);
- }
- }
- }
- public static XElement RetrieveRange(string fileName, string sheetName, string range)
- {
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(fileName, false))
- {
- return RetrieveRange(sDoc, sheetName, range);
- }
- }
- public static XElement RetrieveRange(SpreadsheetDocument sDoc, string sheetName, string range)
- {
- int leftColumn, topRow, rightColumn, bottomRow;
- XlsxTables.ParseRange(range, out leftColumn, out topRow, out rightColumn, out bottomRow);
- return RetrieveRange(sDoc, sheetName, leftColumn, topRow, rightColumn, bottomRow);
- }
- public static XElement RetrieveRange(SmlDocument smlDoc, string sheetName, int leftColumn, int topRow, int rightColumn, int bottomRow)
- {
- using (MemoryStream ms = new MemoryStream())
- {
- ms.Write(smlDoc.DocumentByteArray, 0, smlDoc.DocumentByteArray.Length);
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(ms, false))
- {
- return RetrieveRange(sDoc, sheetName, leftColumn, topRow, rightColumn, bottomRow);
- }
- }
- }
- public static XElement RetrieveRange(string fileName, string sheetName, int leftColumn, int topRow, int rightColumn, int bottomRow)
- {
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(fileName, false))
- {
- return RetrieveRange(sDoc, sheetName, leftColumn, topRow, rightColumn, bottomRow);
- }
- }
- public static XElement RetrieveRange(SpreadsheetDocument sDoc, string sheetName, int leftColumn, int topRow, int rightColumn, int bottomRow)
- {
- var wbXdoc = sDoc.WorkbookPart.GetXDocument();
- var sheet = wbXdoc
- .Root
- .Elements(S.sheets)
- .Elements(S.sheet)
- .FirstOrDefault(s => (string)s.Attribute("name") == sheetName);
- if (sheet == null)
- throw new ArgumentException("Invalid sheet name passed to RetrieveRange", "sheetName");
- var rId = (string)sheet.Attribute(R.id);
- if (rId == null)
- throw new FileFormatException("Invalid spreadsheet");
- var sheetPart = sDoc.WorkbookPart.GetPartById(rId);
- if (sheetPart == null)
- throw new FileFormatException("Invalid spreadsheet");
- var shXDoc = sheetPart.GetXDocument();
- if (sDoc.WorkbookPart.WorkbookStylesPart == null)
- throw new FileFormatException("Invalid spreadsheet. No WorkbookStylesPart.");
- var styleXDoc = sDoc.WorkbookPart.WorkbookStylesPart.GetXDocument();
- // if there is no shared string table, sharedStringTable will be null
- // it will only be used if there is a cell type == "s", in which case, referencing this
- // part would indicate an invalid spreadsheet.
- SharedStringTablePart sharedStringTable = sDoc.WorkbookPart.SharedStringTablePart;
- FixUpCellsThatHaveNoRAtt(shXDoc);
- // assemble the transform
- var sheetData = shXDoc
- .Root
- .Elements(S.sheetData)
- .Elements(S.row)
- .Select(row =>
- {
- // filter
- string ra = (string)row.Attribute("r");
- if (ra == null)
- return null;
- int rowNbr;
- if (!int.TryParse(ra, out rowNbr))
- return null;
- if (rowNbr < topRow)
- return null;
- if (rowNbr > bottomRow)
- return null;
- var cells = row
- .Elements(S.c)
- .Select(cell =>
- {
- var cellAddress = (string)cell.Attribute("r");
- if (cellAddress == null)
- throw new FileFormatException("Invalid spreadsheet - cell does not have r attribute.");
- var splitCellAddress = XlsxTables.SplitAddress(cellAddress);
- var columnAddress = splitCellAddress[0];
- var columnIndex = XlsxTables.ColumnAddressToIndex(columnAddress);
- // filter
- if (columnIndex < leftColumn || columnIndex > rightColumn)
- return null;
- var cellType = (string)cell.Attribute("t");
- string sharedString = null;
- if (cellType == "s")
- {
- int sharedStringIndex;
- string sharedStringBeforeParsing = (string)cell.Element(S.v);
- if (sharedStringBeforeParsing == null)
- sharedStringBeforeParsing = (string)cell.Elements(S._is).Elements(S.t).FirstOrDefault();
- if (sharedStringBeforeParsing == null)
- throw new FileFormatException("Invalid document");
- if (!int.TryParse(sharedStringBeforeParsing, out sharedStringIndex))
- throw new FileFormatException("Invalid document");
- XElement sharedStringElement = null;
- if (sharedStringTable == null)
- throw new FileFormatException("Invalid spreadsheet. Shared string, but no Shared String Part.");
- sharedStringElement =
- sharedStringTable
- .GetXDocument()
- .Root
- .Elements(S.si)
- .Skip(sharedStringIndex)
- .FirstOrDefault();
- if (sharedStringElement == null)
- throw new FileFormatException("Invalid spreadsheet. Shared string reference not valid.");
- sharedString =
- sharedStringElement
- .Descendants(S.t)
- .StringConcatenate(e => (string)e);
- }
- if (sharedString != null)
- {
- XElement cellProps = GetCellProps_NotInTable(sDoc, styleXDoc, cell);
- string value = sharedString;
- string displayValue;
- string color = null;
- if (cellProps != null)
- displayValue = SmlCellFormatter.FormatCell(
- (string)cellProps.Attribute("formatCode"),
- value,
- out color);
- else
- displayValue = value;
- XElement newCell1 = new XElement("Cell",
- new XAttribute("Ref", (string)cell.Attribute("r")),
- new XAttribute("ColumnId", columnAddress),
- new XAttribute("ColumnNumber", columnIndex),
- cell.Attribute("f") != null ? new XAttribute("Formula", (string)cell.Attribute("f")) : null,
- cell.Attribute("s") != null ? new XAttribute("Style", (string)cell.Attribute("s")) : null,
- cell.Attribute("t") != null ? new XAttribute("Type", (string)cell.Attribute("t")) : null,
- cellProps,
- new XElement("Value", value),
- new XElement("DisplayValue", displayValue),
- color != null ? new XElement("DisplayColor", color) : null
- );
- return newCell1;
- }
- else
- {
- var type = (string)cell.Attribute("t");
- XElement value = new XElement("Value", cell.Value);
- if (type != null && type == "inlineStr")
- {
- type = "s";
- }
- XAttribute typeAttr = null;
- if (type != null)
- typeAttr = new XAttribute("Type", type);
- XElement cellProps = GetCellProps_NotInTable(sDoc, styleXDoc, cell);
- string displayValue;
- string color = null;
- if (cellProps != null)
- displayValue = SmlCellFormatter.FormatCell(
- (string)cellProps.Attribute("formatCode"),
- cell.Value,
- out color);
- else
- displayValue = displayValue = SmlCellFormatter.FormatCell(
- (string)"General",
- cell.Value,
- out color);
- XElement newCell2 = new XElement("Cell",
- new XAttribute("Ref", (string)cell.Attribute("r")),
- new XAttribute("ColumnId", columnAddress),
- new XAttribute("ColumnNumber", columnIndex),
- typeAttr,
- cell.Attribute("f") != null ? new XAttribute("Formula", (string)cell.Attribute("f")) : null,
- cell.Attribute("s") != null ? new XAttribute("Style", (string)cell.Attribute("s")) : null,
- cellProps,
- value,
- new XElement("DisplayValue", displayValue),
- color != null ? new XElement("DisplayColor", color) : null);
- return newCell2;
- }
- });
- XElement dataRow = new XElement("Row",
- row.Attribute("r") != null ? new XAttribute("RowNumber", (int)row.Attribute("r")) : null,
- cells);
- return dataRow;
- });
- var dataProps = GetDataProps(shXDoc);
- XElement data = new XElement("Data",
- dataProps,
- sheetData);
- return data;
- }
- // Sometimes encounter cells that have no r attribute, so infer it if possible.
- // These are invalid spreadsheets, but attempt to get the data anyway.
- private static void FixUpCellsThatHaveNoRAtt(XDocument shXDoc)
- {
- // if there are any rows that have all cells with no r attribute, then fix them up
- var invalidRows = shXDoc
- .Descendants(S.row)
- .Where(r => ! r.Elements(S.c).Any(c => c.Attribute("r") != null))
- .ToList();
- foreach (var row in invalidRows)
- {
- var rowNumberStr = (string)row.Attribute("r");
- var colNumber = 0;
- foreach (var cell in row.Elements(S.c))
- {
- var newCellRef = XlsxTables.IndexToColumnAddress(colNumber) + rowNumberStr;
- cell.Add(new XAttribute("r", newCellRef));
- }
- }
- // repeat iteratively until no further fixes can be made
- while (true)
- {
- var invalidCells = shXDoc
- .Descendants(S.c)
- .Where(c => c.Attribute("r") == null)
- .ToList();
- bool didFixup = false;
- foreach (var cell in invalidCells)
- {
- var followingCell = cell.ElementsAfterSelf(S.c).FirstOrDefault();
- if (followingCell != null)
- {
- var followingR = (string)followingCell.Attribute("r");
- if (followingR != null)
- {
- var spl = XlsxTables.SplitAddress(followingR);
- var colIdxFollowing = XlsxTables.ColumnAddressToIndex(spl[0]);
- var newRef = XlsxTables.IndexToColumnAddress(colIdxFollowing - 1) + spl[1];
- cell.Add(new XAttribute("r", newRef));
- didFixup = true;
- }
- else
- {
- didFixup = FixUpBasedOnPrecedingCell(didFixup, cell);
- }
- }
- else
- {
- didFixup = FixUpBasedOnPrecedingCell(didFixup, cell);
- }
- }
- if (!didFixup)
- break;
- }
- }
- private static bool FixUpBasedOnPrecedingCell(bool didFixup, XElement cell)
- {
- XElement precedingCell = GetPrevousElement(cell);
- if (precedingCell != null)
- {
- var precedingR = (string)precedingCell.Attribute("r");
- if (precedingR != null)
- {
- var spl = XlsxTables.SplitAddress(precedingR);
- var colIdxFollowing = XlsxTables.ColumnAddressToIndex(spl[0]);
- var newRef = XlsxTables.IndexToColumnAddress(colIdxFollowing + 1) + spl[1];
- cell.Add(new XAttribute("r", newRef));
- didFixup = true;
- }
- }
- return didFixup;
- }
- private static XElement GetPrevousElement(XElement element)
- {
- XElement previousElement = null;
- XNode currentNode = element;
- while (true)
- {
- if (currentNode.PreviousNode == null)
- return null;
- previousElement = currentNode.PreviousNode as XElement;
- if (previousElement != null)
- return previousElement;
- currentNode = currentNode.PreviousNode;
- }
- }
- public static XElement RetrieveTable(SmlDocument smlDoc, string sheetName, string tableName)
- {
- using (MemoryStream ms = new MemoryStream())
- {
- ms.Write(smlDoc.DocumentByteArray, 0, smlDoc.DocumentByteArray.Length);
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(ms, false))
- {
- return RetrieveTable(sDoc, tableName);
- }
- }
- }
- public static XElement RetrieveTable(string fileName, string tableName)
- {
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(fileName, false))
- {
- return RetrieveTable(sDoc, tableName);
- }
- }
- public static XElement RetrieveTable(SpreadsheetDocument sDoc, string tableName)
- {
- var table = sDoc.Table(tableName);
- if (table == null)
- throw new ArgumentException("Table not found", "tableName");
- var styleXDoc = sDoc.WorkbookPart.WorkbookStylesPart.GetXDocument();
- var r = table.Ref;
- int leftColumn, topRow, rightColumn, bottomRow;
- XlsxTables.ParseRange(r, out leftColumn, out topRow, out rightColumn, out bottomRow);
- var shXDoc = table.Parent.GetXDocument();
- FixUpCellsThatHaveNoRAtt(shXDoc);
- // assemble the transform
- var columns = new XElement("Columns",
- table.TableColumns().Select(tc =>
- {
- var colXElement = new XElement("Column",
- tc.Name != null ? new XAttribute("Name", tc.Name) : null,
- tc.UniqueName != null ? new XAttribute("UniqueName", tc.UniqueName) : null,
- new XAttribute("ColumnIndex", tc.ColumnIndex),
- new XAttribute("Id", tc.Id),
- tc.DataDxfId != null ? new XAttribute("DataDxfId", tc.DataDxfId) : null,
- tc.QueryTableFieldId != null ? new XAttribute("QueryTableFieldId", tc.QueryTableFieldId) : null);
- return colXElement;
- }));
- var dataProps = GetDataProps(shXDoc);
- var data = new XElement("Data",
- dataProps,
- table.TableRows().Select(tr =>
- {
- int rowRef;
- if (!int.TryParse(tr.Row.RowId, out rowRef))
- throw new FileFormatException("Invalid spreadsheet");
- // filter
- if (rowRef < topRow || rowRef > bottomRow)
- return null;
- var cellData = tr.Row.Cells().Select(tc =>
- {
- // filter
- var columnIndex = tc.ColumnIndex;
- if (columnIndex < leftColumn || columnIndex > rightColumn)
- return null;
- XElement cellProps = GetCellProps_InTable(sDoc, styleXDoc, table, tc);
- if (tc.SharedString != null)
- {
- string displayValue;
- string color = null;
- if (cellProps != null)
- displayValue = SmlCellFormatter.FormatCell(
- (string)cellProps.Attribute("formatCode"),
- tc.SharedString,
- out color);
- else
- displayValue = tc.SharedString;
- XElement newCell1 = new XElement("Cell",
- tc.CellElement != null ? new XAttribute("Ref", (string)tc.CellElement.Attribute("r")) : null,
- tc.ColumnAddress != null ? new XAttribute("ColumnId", tc.ColumnAddress) : null,
- new XAttribute("ColumnNumber", tc.ColumnIndex),
- tc.Type != null ? new XAttribute("Type", "s") : null,
- tc.Formula != null ? new XAttribute("Formula", tc.Formula) : null,
- tc.Style != null ? new XAttribute("Style", tc.Style) : null,
- cellProps,
- new XElement("Value", tc.SharedString),
- new XElement("DisplayValue", displayValue),
- color != null ? new XElement("DisplayColor", color) : null);
- return newCell1;
- }
- else
- {
- XAttribute type = null;
- if (tc.Type != null)
- {
- if (tc.Type == "inlineStr")
- type = new XAttribute("Type", "s");
- else
- type = new XAttribute("Type", tc.Type);
- }
- string displayValue;
- string color = null;
- if (cellProps != null)
- displayValue = SmlCellFormatter.FormatCell(
- (string)cellProps.Attribute("formatCode"),
- tc.Value,
- out color);
- else
- displayValue = SmlCellFormatter.FormatCell(
- (string)"General",
- tc.Value,
- out color);
- XElement newCell = new XElement("Cell",
- tc.CellElement != null ? new XAttribute("Ref", (string)tc.CellElement.Attribute("r")) : null,
- tc.ColumnAddress != null ? new XAttribute("ColumnId", tc.ColumnAddress) : null,
- new XAttribute("ColumnNumber", tc.ColumnIndex),
- type,
- tc.Formula != null ? new XAttribute("Formula", tc.Formula) : null,
- tc.Style != null ? new XAttribute("Style", tc.Style) : null,
- cellProps,
- new XElement("Value", tc.Value),
- new XElement("DisplayValue", displayValue),
- color != null ? new XElement("DisplayColor", color) : null);
- return newCell;
- }
- });
- var rowProps = GetRowProps(tr.Row.RowElement);
- var newRow = new XElement("Row",
- rowProps,
- new XAttribute("RowNumber", tr.Row.RowId),
- cellData);
- return newRow;
- }));
- XElement tableProps = GetTableProps(table);
- var tableXml = new XElement("Table",
- tableProps,
- table.TableName != null ? new XAttribute("TableName", table.TableName) : null,
- table.DisplayName != null ? new XAttribute("DisplayName", table.DisplayName) : null,
- table.Ref != null ? new XAttribute("Ref", table.Ref) : null,
- table.HeaderRowCount != null ? new XAttribute("HeaderRowCount", table.HeaderRowCount) : null,
- table.TotalsRowCount != null ? new XAttribute("TotalsRowCount", table.TotalsRowCount) : null,
- columns,
- data);
- return tableXml;
- }
- public static string[] SheetNames(SmlDocument smlDoc)
- {
- using (MemoryStream ms = new MemoryStream())
- {
- ms.Write(smlDoc.DocumentByteArray, 0, smlDoc.DocumentByteArray.Length);
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(ms, false))
- {
- return SheetNames(sDoc);
- }
- }
- }
- public static string[] SheetNames(string fileName)
- {
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(fileName, false))
- {
- return SheetNames(sDoc);
- }
- }
- public static string[] SheetNames(SpreadsheetDocument sDoc)
- {
- var workbookXDoc = sDoc.WorkbookPart.GetXDocument();
- var sheetNames = workbookXDoc.Root.Elements(S.sheets).Elements(S.sheet).Attributes("name").Select(a => (string)a).ToArray();
- return sheetNames;
- }
- public static string[] TableNames(SmlDocument smlDoc)
- {
- using (MemoryStream ms = new MemoryStream())
- {
- ms.Write(smlDoc.DocumentByteArray, 0, smlDoc.DocumentByteArray.Length);
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(ms, false))
- {
- return TableNames(sDoc);
- }
- }
- }
- public static string[] TableNames(string fileName)
- {
- using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(fileName, false))
- {
- return TableNames(sDoc);
- }
- }
- public static string[] TableNames(SpreadsheetDocument sDoc)
- {
- var workbookXDoc = sDoc.WorkbookPart.GetXDocument();
- var sheets = workbookXDoc.Root.Elements(S.sheets).Elements(S.sheet);
- var tableNames = sheets.Select(sh =>
- {
- var rId = (string)sh.Attribute(R.id);
- var sheetPart = sDoc.WorkbookPart.GetPartById(rId);
- var sheetXDoc = sheetPart.GetXDocument();
- var tableParts = sheetXDoc.Root.Element(S.tableParts);
- if (tableParts == null)
- return new List<string>();
- var tableNames2 = tableParts
- .Elements(S.tablePart)
- .Select(tp =>
- {
- var tpRId = (string)tp.Attribute(R.id);
- var tpart = sheetPart.GetPartById(tpRId);
- var tpxd = tpart.GetXDocument();
- var name = (string)tpxd.Root.Attribute("name");
- return name;
- })
- .ToList();
- return tableNames2;
- })
- .SelectMany(m => m)
- .ToArray();
- return tableNames;
- }
- private static XElement GetTableProps(Table table)
- {
- XElement tableProps = new XElement("TableProps");
- XElement tableStyleInfo = table.TableStyleInfo;
- if (tableStyleInfo != null)
- {
- var newTableStyleInfo = TransformRemoveNamespace(tableStyleInfo);
- tableProps.Add(newTableStyleInfo);
- }
- if (!tableProps.HasElements && !tableProps.HasElements)
- tableProps = null;
- return tableProps;
- }
- private static XElement GetDataProps(XDocument shXDoc)
- {
- var sheetFormatPr = shXDoc.Root.Element(S.sheetFormatPr);
- if (sheetFormatPr != null && sheetFormatPr.Attribute("defaultColWidth") == null)
- sheetFormatPr.Add(new XAttribute("defaultColWidth", "9.25"));
- if (sheetFormatPr != null && sheetFormatPr.Attribute("defaultRowHeight") == null)
- sheetFormatPr.Add(new XAttribute("defaultRowHeight", "14.25"));
- var mergeCells = TransformRemoveNamespace(shXDoc.Root.Element(S.mergeCells));
- var dataProps = new XElement("DataProps",
- TransformRemoveNamespace(sheetFormatPr),
- TransformRemoveNamespace(shXDoc.Root.Element(S.cols)),
- mergeCells);
-
- if (!dataProps.HasAttributes && !dataProps.HasElements)
- dataProps = null;
- return dataProps;
- }
- private static XElement GetRowProps(XElement rowElement)
- {
- var rowProps = new XElement("RowProps");
- var ht = rowElement.Attribute("ht");
- if (ht != null)
- rowProps.Add(ht);
- var dyDescent = rowElement.Attribute(x14ac + "dyDescent");
- if (dyDescent != null)
- rowProps.Add(new XAttribute("dyDescent", (string)dyDescent));
- if (!rowProps.HasAttributes && !rowProps.HasElements)
- rowProps = null;
- return rowProps;
- }
- private static XElement GetCellProps_NotInTable(SpreadsheetDocument sDoc, XDocument styleXDoc, XElement cell)
- {
- var cellProps = new XElement("CellProps");
- var style = (int?)cell.Attribute("s");
- if (style == null)
- return cellProps;
- var xf = styleXDoc
- .Root
- .Elements(S.cellXfs)
- .Elements(S.xf)
- .Skip((int)style)
- .FirstOrDefault();
- var numFmtId = (int?)xf.Attribute("numFmtId");
- if (numFmtId != null)
- AddNumFmtIdAndFormatCode(styleXDoc, cellProps, numFmtId);
- var masterXfId = (int?)xf.Attribute("xfId");
- if (masterXfId != null)
- {
- var masterXf = styleXDoc
- .Root
- .Elements(S.cellStyleXfs)
- .Elements(S.xf)
- .Skip((int)masterXfId)
- .FirstOrDefault();
- if (masterXf != null)
- AddFormattingToCellProps(styleXDoc, cellProps, masterXf);
- }
- AddFormattingToCellProps(styleXDoc, cellProps, xf);
- AugmentAndCleanUpProps(cellProps);
- if (!cellProps.HasElements && !cellProps.HasAttributes)
- return null;
- return cellProps;
- }
- private static XElement GetCellProps_InTable(SpreadsheetDocument sDoc, XDocument styleXDoc, Table table, Cell tc)
- {
- var style = tc.Style;
- if (style == null)
- return null;
- var colIdStr = tc.ColumnAddress;
- int colNbr = XlsxTables.ColumnAddressToIndex(colIdStr);
- TableColumn column = table.TableColumns().FirstOrDefault(z => z.ColumnNumber == colNbr);
- if (column == null)
- throw new FileFormatException("Invalid spreadsheet");
- var cellProps = new XElement("CellProps");
- var d = column.DataDxfId;
- if (d != null)
- {
- var dataDxf = styleXDoc
- .Root
- .Elements(S.dxfs)
- .Elements(S.dxf)
- .Skip((int)d)
- .FirstOrDefault();
- if (dataDxf == null)
- throw new FileFormatException("Invalid spreadsheet");
- var numFmt = dataDxf.Element(S.numFmt);
- if (numFmt != null)
- {
- var numFmtId = (int?)numFmt.Attribute("numFmtId");
- if (numFmtId != null)
- cellProps.Add(new XAttribute("numFmtId", numFmtId));
- var formatCode = (string)numFmt.Attribute("formatCode");
- if (formatCode != null)
- cellProps.Add(new XAttribute("formatCode", formatCode));
- }
- }
- var xf = styleXDoc.Root
- .Elements(S.cellXfs)
- .Elements(S.xf)
- .Skip((int)style)
- .FirstOrDefault();
- if (xf == null)
- throw new FileFormatException("Invalid spreadsheet");
- // if xf has different numFmtId, then replace the ones from the table definition
- var numFmtId2 = (int?)xf.Attribute("numFmtId");
- if (numFmtId2 != null)
- AddNumFmtIdAndFormatCode(styleXDoc, cellProps, numFmtId2);
- var masterXfId = (int?)xf.Attribute("xfId");
- if (masterXfId != null)
- {
- var masterXf = styleXDoc
- .Root
- .Elements(S.cellStyleXfs)
- .Elements(S.xf)
- .Skip((int)masterXfId)
- .FirstOrDefault();
- if (masterXf != null)
- AddFormattingToCellProps(styleXDoc, cellProps, masterXf);
- }
- AddFormattingToCellProps(styleXDoc, cellProps, xf);
- AugmentAndCleanUpProps(cellProps);
- if (!cellProps.HasElements && !cellProps.HasAttributes)
- return null;
- return cellProps;
- }
- private static void AddNumFmtIdAndFormatCode(XDocument styleXDoc, XElement props, int? numFmtId)
- {
- var existingNumFmtId = props.Attribute("numFmtId");
- if (existingNumFmtId != null)
- existingNumFmtId.Value = numFmtId.ToString();
- else
- props.Add(new XAttribute("numFmtId", numFmtId));
- var numFmt = styleXDoc
- .Root
- .Elements(S.numFmts)
- .Elements(S.numFmt)
- .FirstOrDefault(z => (int)z.Attribute("numFmtId") == numFmtId);
- if (numFmt == null)
- {
- var formatCode = GetFormatCodeFromFmtId((int)numFmtId);
- if (formatCode != null)
- {
- var existingFormatCode = props.Attribute("formatCode");
- if (existingFormatCode != null)
- existingFormatCode.Value = formatCode;
- else
- props.Add(new XAttribute("formatCode", formatCode));
- }
- }
- else
- {
- var formatCode = (string)numFmt.Attribute("formatCode");
- if (formatCode != null)
- {
- var existingFormatCode = props.Attribute("formatCode");
- if (existingFormatCode != null)
- existingFormatCode.Value = formatCode;
- else
- props.Add(new XAttribute("formatCode", formatCode));
- }
- }
- }
- private static void AddFormattingToCellProps(XDocument styleXDoc, XElement props, XElement xf)
- {
- MoveBooleanAttribute(props, xf, "applyAlignment");
- MoveBooleanAttribute(props, xf, "applyBorder");
- MoveBooleanAttribute(props, xf, "applyFill");
- MoveBooleanAttribute(props, xf, "applyFont");
- MoveBooleanAttribute(props, xf, "applyNumberFormat");
- int? borderId = (int?)xf.Attribute("borderId");
- int? fillId = (int?)xf.Attribute("fillId");
- int? fontId = (int?)xf.Attribute("fontId");
- if (fontId != null)
- {
- var fontElement = styleXDoc
- .Root
- .Elements(S.fonts)
- .Elements(S.font)
- .Skip((int)fontId)
- .FirstOrDefault();
- if (fontElement != null)
- {
- var newFontElement = (XElement)TransformRemoveNamespace(fontElement);
- AddOrReplaceElement(props, newFontElement);
- }
- }
- if (fillId != null)
- {
- var fillElement = styleXDoc
- .Root
- .Elements(S.fills)
- .Elements(S.fill)
- .Skip((int)fillId)
- .FirstOrDefault();
- if (fillElement != null)
- {
- var newFillElement = (XElement)TransformRemoveNamespace(fillElement);
- AddOrReplaceElement(props, newFillElement);
- }
- }
- if (borderId != null)
- {
- var borderElement = styleXDoc
- .Root
- .Elements(S.borders)
- .Elements(S.border)
- .Skip((int)borderId)
- .FirstOrDefault();
- if (borderElement != null)
- {
- var newborderElement = (XElement)TransformRemoveNamespace(borderElement);
- AddOrReplaceElement(props, newborderElement);
- }
- }
- if (xf.Element(S.alignment) != null)
- {
- var newAlignmentElement = (XElement)TransformRemoveNamespace(xf.Element(S.alignment));
- AddOrReplaceElement(props, newAlignmentElement);
- }
- }
- private static void MoveBooleanAttribute(XElement props, XElement xf, XName attributeName)
- {
- bool attrValue = ConvertAttributeToBool(xf.Attribute(attributeName));
- if (attrValue)
- {
- if (props.Attribute(attributeName) == null)
- props.Add(new XAttribute(attributeName, attrValue ? "1" : "0"));
- else
- props.Attribute(attributeName).Value = attrValue ? "1" : "0";
- }
- }
- public static string[] IndexedColors = new string[] {
- "00000000",
- "00FFFFFF",
- "00FF0000",
- "0000FF00",
- "000000FF",
- "00FFFF00",
- "00FF00FF",
- "0000FFFF",
- "00000000",
- "00FFFFFF",
- "00FF0000",
- "0000FF00",
- "000000FF",
- "00FFFF00",
- "00FF00FF",
- "0000FFFF",
- "00800000",
- "00008000",
- "00000080",
- "00808000",
- "00800080",
- "00008080",
- "00C0C0C0",
- "00808080",
- "009999FF",
- "00993366",
- "00FFFFCC",
- "00CCFFFF",
- "00660066",
- "00FF8080",
- "000066CC",
- "00CCCCFF",
- "00000080",
- "00FF00FF",
- "00FFFF00",
- "0000FFFF",
- "00800080",
- "00800000",
- "00008080",
- "000000FF",
- "0000CCFF",
- "00CCFFFF",
- "00CCFFCC",
- "00FFFF99",
- "0099CCFF",
- "00FF99CC",
- "00CC99FF",
- "00FFCC99",
- "003366FF",
- "0033CCCC",
- "0099CC00",
- "00FFCC00",
- "00FF9900",
- "00FF6600",
- "00666699",
- "00969696",
- "00003366",
- "00339966",
- "00003300",
- "00333300",
- "00993300",
- "00993366",
- "00333399",
- "00333333",
- "System Foreground",
- "System Background",
- };
- private static string[] FontFamilyList = new string[] {
- "Not applicable",
- "Roman",
- "Swiss",
- "Modern",
- "Script",
- "Decorative",
- };
- private static void AugmentAndCleanUpProps(XElement props)
- {
- foreach (var color in props.Descendants("color").Where(c => c.Attribute("indexed") != null).ToList())
- {
- var idx = (int)color.Attribute("indexed");
- if (idx < IndexedColors.Length)
- {
- color.Add(new XAttribute("val", IndexedColors[idx]));
- }
- color.Attribute("indexed").Remove();
- }
- foreach (var family in props.Descendants("family").ToList())
- {
- var fam = (int?)family.Attribute("val");
- if (fam != null)
- {
- if (fam < FontFamilyList.Length)
- {
- family.Attribute("val").Remove();
- family.Add(new XAttribute("val", FontFamilyList[(int)fam]));
- }
- }
- }
- foreach (var border in props.Descendants("border").ToList())
- {
- RemoveIfEmpty(border.Element("left"));
- RemoveIfEmpty(border.Element("right"));
- RemoveIfEmpty(border.Element("top"));
- RemoveIfEmpty(border.Element("bottom"));
- RemoveIfEmpty(border.Element("diagonal"));
- if (!border.HasAttributes && !border.HasElements)
- border.Remove();
- }
- foreach (var fill in props.Descendants("fill").ToList())
- {
- fill.Elements("patternFill").Where(pf => (string)pf.Attribute("patternType") == "none").Remove();
- if (!fill.HasAttributes && !fill.HasElements)
- fill.Remove();
- }
- }
- private static void RemoveIfEmpty(XElement xElement)
- {
- if (xElement == null)
- return;
- if (!xElement.HasAttributes && !xElement.HasElements)
- xElement.Remove();
- }
- private static object TransformRemoveNamespace(XNode node)
- {
- if (node == null)
- return null;
- XElement element = node as XElement;
- if (element != null)
- {
- return new XElement(element.Name.LocalName,
- element.Attributes().Select(a => new XAttribute(a.Name.LocalName, (string)a)).OrderBy(a => (string)a.Name.LocalName),
- element.Nodes().Select(n => TransformRemoveNamespace(n)));
- }
- return node;
- }
- private static string GetFormatCodeFromFmtId(int fmtId)
- {
- switch (fmtId)
- {
- case 0: return "General";
- case 1: return "0";
- case 2: return "0.00";
- case 3: return "#,##0";
- case 4: return "#,##0.00";
- case 9: return "0%";
- case 10: return "0.00%";
- case 11: return "0.00E+00";
- case 12: return "# ?/?";
- case 13: return "# ??/??";
- case 14: return "mm-dd-yy";
- case 15: return "d-mmm-yy";
- case 16: return "d-mmm";
- case 17: return "mmm-yy";
- case 18: return "h:mm AM/PM";
- case 19: return "h:mm:ss AM/PM";
- case 20: return "h:mm";
- case 21: return "h:mm:ss";
- case 22: return "22 m/d/yy h:mm";
- case 37: return "#,##0 ;(#,##0)";
- case 38: return "#,##0 ;[Red](#,##0)";
- case 39: return "#,##0.00;(#,##0.00)";
- case 40: return "#,##0.00;[Red](#,##0.00)";
- case 45: return "mm:ss";
- case 46: return "[h]:mm:ss";
- case 47: return "mmss.0";
- case 48: return "##0.0E+0";
- case 49: return "@";
- default: return null;
- }
- }
- private static void AddOrReplaceElement(XElement props, XName childElementName, int value)
- {
- var existingElement = props.Element(childElementName);
- if (existingElement != null)
- existingElement.ReplaceWith(new XElement(childElementName, new XAttribute("Val", value)));
- else
- props.Add(new XElement(childElementName, new XAttribute("Val", value)));
- }
- private static void AddOrReplaceElement(XElement props, XName childElementName, string value)
- {
- var existingElement = props.Element(childElementName);
- if (existingElement != null)
- existingElement.ReplaceWith(new XElement(childElementName, new XAttribute("Val", value)));
- else
- props.Add(new XElement(childElementName, new XAttribute("Val", value)));
- }
- private static void AddOrReplaceElement(XElement props, XElement element)
- {
- var existingElement = props.Element(element.Name);
- if (existingElement != null)
- existingElement.ReplaceWith(element);
- else
- props.Add(element);
- }
- private static bool ConvertAttributeToBool(XAttribute xAttribute)
- {
- string applyNumberFormatStr = (string)xAttribute;
- bool returnValue = false;
- if (applyNumberFormatStr != null)
- {
- if (applyNumberFormatStr == "1")
- returnValue = true;
- if (applyNumberFormatStr.Substring(0, 1).ToUpper() == "T")
- returnValue = true;
- }
- return returnValue;
- }
- private static XNamespace x14ac = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac";
- }
- }
|