WorksheetAccessor.cs 95 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185
  1. // Copyright (c) Microsoft. All rights reserved.
  2. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  3. using System;
  4. using System.Text;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Xml.Linq;
  8. using DocumentFormat.OpenXml.Packaging;
  9. using System.Xml;
  10. using ExcelFormula;
  11. namespace OpenXmlPowerTools
  12. {
  13. // Classes for "bulk load" of a spreadsheet
  14. public class MemorySpreadsheet
  15. {
  16. private SortedList<int, MemoryRow> rowList;
  17. public MemorySpreadsheet()
  18. {
  19. rowList = new SortedList<int, MemoryRow>();
  20. }
  21. public void SetCellValue(int row, int column, object value)
  22. {
  23. if (!rowList.ContainsKey(row))
  24. rowList.Add(row, new MemoryRow(row));
  25. MemoryRow mr = rowList[row];
  26. mr.SetCell(new MemoryCell(column, value));
  27. }
  28. public void SetCellValue(int row, int column, object value, int styleIndex)
  29. {
  30. if (!rowList.ContainsKey(row))
  31. rowList.Add(row, new MemoryRow(row));
  32. MemoryRow mr = rowList[row];
  33. mr.SetCell(new MemoryCell(column, value, styleIndex));
  34. }
  35. public object GetCellValue(int row, int column)
  36. {
  37. if (!rowList.ContainsKey(row))
  38. return null;
  39. MemoryCell cell = rowList[row].GetCell(column);
  40. if (cell == null)
  41. return null;
  42. return cell.GetValue();
  43. }
  44. public XElement GetElements()
  45. {
  46. XElement root = new XElement(S.sheetData);
  47. foreach (KeyValuePair<int, MemoryRow> item in rowList)
  48. root.Add(item.Value.GetElements());
  49. return root;
  50. }
  51. }
  52. public class MemoryRow
  53. {
  54. private int row;
  55. private SortedList<int, MemoryCell> cellList;
  56. public MemoryRow(int Row)
  57. {
  58. row = Row;
  59. cellList = new SortedList<int, MemoryCell>();
  60. }
  61. public MemoryCell GetCell(int column)
  62. {
  63. if (!cellList.ContainsKey(column))
  64. return null;
  65. return cellList[column];
  66. }
  67. public void SetCell(MemoryCell cell)
  68. {
  69. if (cellList.ContainsKey(cell.GetColumn()))
  70. cellList.Remove(cell.GetColumn());
  71. cellList.Add(cell.GetColumn(), cell);
  72. }
  73. public XElement GetElements()
  74. {
  75. XElement root = new XElement(S.row, new XAttribute(NoNamespace.r, row));
  76. foreach (KeyValuePair<int, MemoryCell> item in cellList)
  77. root.Add(item.Value.GetElements(row));
  78. return root;
  79. }
  80. }
  81. public class MemoryCell
  82. {
  83. private int column;
  84. private object cellValue;
  85. private int styleIndex;
  86. public MemoryCell(int col, object value)
  87. {
  88. column = col;
  89. cellValue = value;
  90. }
  91. public MemoryCell(int col, object value, int style)
  92. {
  93. column = col;
  94. cellValue = value;
  95. styleIndex = style;
  96. }
  97. public int GetColumn()
  98. {
  99. return column;
  100. }
  101. public object GetValue()
  102. {
  103. return cellValue;
  104. }
  105. public int GetStyleIndex()
  106. {
  107. return styleIndex;
  108. }
  109. public XElement GetElements(int row)
  110. {
  111. string cellReference = WorksheetAccessor.GetColumnId(column) + row.ToString();
  112. XElement newCell = null;
  113. if (cellValue is int || cellValue is double)
  114. newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XElement(S.v, cellValue.ToString()));
  115. else if (cellValue is bool)
  116. newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XAttribute(NoNamespace.t, "b"), new XElement(S.v, (bool)cellValue ? "1" : "0"));
  117. else if (cellValue is string)
  118. {
  119. newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XAttribute(NoNamespace.t, "inlineStr"),
  120. new XElement(S._is, new XElement(S.t, cellValue.ToString())));
  121. }
  122. if (newCell == null)
  123. throw new ArgumentException("Invalid cell type.");
  124. if (styleIndex != 0)
  125. newCell.Add(new XAttribute(NoNamespace.s, styleIndex));
  126. return newCell;
  127. }
  128. }
  129. // Static methods to modify worksheets in SpreadsheetML
  130. public class WorksheetAccessor
  131. {
  132. private static XNamespace ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
  133. private static XNamespace relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
  134. // Finds the WorksheetPart by sheet name
  135. public static WorksheetPart GetWorksheet(SpreadsheetDocument document, string worksheetName)
  136. {
  137. XDocument workbook = document.WorkbookPart.GetXDocument();
  138. return (WorksheetPart)document.WorkbookPart.GetPartById(
  139. workbook.Root.Element(S.sheets).Elements(S.sheet).Where(
  140. s => s.Attribute(NoNamespace.name).Value.ToLower().Equals(worksheetName.ToLower()))
  141. .FirstOrDefault().Attribute(R.id).Value);
  142. }
  143. // Creates a new worksheet with the specified name
  144. public static WorksheetPart AddWorksheet(SpreadsheetDocument document, string worksheetName)
  145. {
  146. // Create the empty sheet
  147. WorksheetPart worksheetPart = document.WorkbookPart.AddNewPart<WorksheetPart>();
  148. worksheetPart.PutXDocument(new XDocument(
  149. new XElement(S.worksheet, new XAttribute("xmlns", S.s), new XAttribute(XNamespace.Xmlns + "r", R.r),
  150. new XElement(S.sheetData))));
  151. XDocument wb = document.WorkbookPart.GetXDocument();
  152. // Generate a unique sheet ID number
  153. int sheetId = 1;
  154. if (wb.Root.Element(S.sheets).Elements(S.sheet).Count() != 0)
  155. sheetId = wb.Root.Element(S.sheets).Elements(S.sheet).Max(n => Convert.ToInt32(n.Attribute(NoNamespace.sheetId).Value)) + 1;
  156. // If name is null, generate a name based on the sheet ID
  157. if (worksheetName == null)
  158. worksheetName = "Sheet" + sheetId.ToString();
  159. // Create the new sheet element in the workbook
  160. wb.Root.Element(S.sheets).Add(new XElement(S.sheet,
  161. new XAttribute(NoNamespace.name, worksheetName),
  162. new XAttribute(NoNamespace.sheetId, sheetId),
  163. new XAttribute(R.id, document.WorkbookPart.GetIdOfPart(worksheetPart))));
  164. document.WorkbookPart.PutXDocument();
  165. return worksheetPart;
  166. }
  167. // Creates a new worksheet with the specified name and contents from a memory spreadsheet
  168. public static void SetSheetContents(SpreadsheetDocument document, WorksheetPart worksheet, MemorySpreadsheet contents)
  169. {
  170. XDocument worksheetXDocument = worksheet.GetXDocument();
  171. worksheetXDocument.Root.Element(S.sheetData).ReplaceWith(contents.GetElements());
  172. worksheet.PutXDocument();
  173. }
  174. // Translates the column number to the column reference string (e.g. 1 -> A, 2-> B)
  175. public static string GetColumnId(int columnNumber)
  176. {
  177. string result = "";
  178. do
  179. {
  180. result = ((char)((columnNumber - 1) % 26 + (int)'A')).ToString() + result;
  181. columnNumber = (columnNumber - 1) / 26;
  182. } while (columnNumber != 0);
  183. return result;
  184. }
  185. // Gets the value of the specified cell
  186. // Returned object can be double/Double, int/Int32, bool/Boolean or string/String types
  187. public static object GetCellValue(SpreadsheetDocument document, WorksheetPart worksheet, int column, int row)
  188. {
  189. XDocument worksheetXDocument = worksheet.GetXDocument();
  190. XElement cellValue = GetCell(worksheetXDocument, column, row);
  191. if (cellValue != null)
  192. {
  193. if (cellValue.Attribute(NoNamespace.t) == null)
  194. {
  195. string value = cellValue.Element(S.v).Value;
  196. if (value.Contains("."))
  197. return Convert.ToDouble(value);
  198. return Convert.ToInt32(value);
  199. }
  200. switch (cellValue.Attribute(NoNamespace.t).Value)
  201. {
  202. case "b":
  203. return (cellValue.Element(S.v).Value == "1");
  204. case "s":
  205. return GetSharedString(document, System.Convert.ToInt32(cellValue.Element(S.v).Value));
  206. case "inlineStr":
  207. return cellValue.Element(S._is).Element(S.t).Value;
  208. }
  209. }
  210. return null;
  211. }
  212. // Finds the shared string using its index
  213. private static string GetSharedString(SpreadsheetDocument document, int index)
  214. {
  215. XDocument sharedStringsXDocument = document.WorkbookPart.SharedStringTablePart.GetXDocument();
  216. return sharedStringsXDocument.Root.Elements().ElementAt<XElement>(index).Value;
  217. }
  218. // Gets the cell element (c) for the specified cell
  219. private static XElement GetCell(XDocument worksheet, int column, int row)
  220. {
  221. string cellReference = GetColumnId(column) + row.ToString();
  222. XElement rowElement = worksheet.Root
  223. .Element(S.sheetData)
  224. .Elements(S.row)
  225. .Where(r => r.Attribute(NoNamespace.r).Value.Equals(row.ToString())).FirstOrDefault<XElement>();
  226. if (rowElement == null)
  227. return null;
  228. return rowElement.Elements(S.c).Where(c => c.Attribute(NoNamespace.r).Value.Equals(cellReference)).FirstOrDefault<XElement>();
  229. }
  230. // Sets the value for the specified cell
  231. // The "value" must be double/Double, int/Int32, bool/Boolean or string/String type
  232. public static void SetCellValue(SpreadsheetDocument document, WorksheetPart worksheet, int row, int column, object value)
  233. {
  234. XDocument worksheetXDocument = worksheet.GetXDocument();
  235. string cellReference = GetColumnId(column) + row.ToString();
  236. XElement newCell = null;
  237. if (value is int || value is double)
  238. newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XElement(S.v, value.ToString()));
  239. else if (value is bool)
  240. newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XAttribute(NoNamespace.t, "b"), new XElement(S.v, (bool)value ? "1" : "0"));
  241. else if (value is string)
  242. {
  243. newCell = new XElement(S.c, new XAttribute(NoNamespace.r, cellReference), new XAttribute(NoNamespace.t, "inlineStr"),
  244. new XElement(S._is, new XElement(S.t, value.ToString())));
  245. }
  246. if (newCell == null)
  247. throw new ArgumentException("Invalid cell type.");
  248. SetCell(worksheetXDocument, newCell);
  249. }
  250. // Sets the specified cell
  251. private static void SetCell(XDocument worksheetXDocument, XElement newCell)
  252. {
  253. int row;
  254. int column;
  255. string cellReference = newCell.Attribute(NoNamespace.r).Value;
  256. GetRowColumn(cellReference, out row, out column);
  257. // Find the row containing the cell to add the value to
  258. XElement rowElement = worksheetXDocument.Root
  259. .Element(S.sheetData)
  260. .Elements(S.row)
  261. .Where(t => t.Attribute(NoNamespace.r).Value == row.ToString())
  262. .FirstOrDefault();
  263. if (rowElement == null)
  264. {
  265. //row element does not exist
  266. //create a new one
  267. rowElement = CreateEmptyRow(row);
  268. //row elements must appear in order inside sheetData element
  269. if (worksheetXDocument.Root.Element(S.sheetData).HasElements)
  270. { //if there are more rows already defined at sheetData element
  271. //find the row with the inmediate higher index for the row containing the cell to set the value to
  272. XElement rowAfterElement = FindRowAfter(worksheetXDocument, row);
  273. //if there is a row with an inmediate higher index already defined at sheetData
  274. if (rowAfterElement != null)
  275. {
  276. //add the new row before the row with an inmediate higher index
  277. rowAfterElement.AddBeforeSelf(rowElement);
  278. }
  279. else
  280. { //this row is going to be the one with the highest index (add it as the last element for sheetData)
  281. worksheetXDocument.Root.Element(S.sheetData).Elements(S.row).Last().AddAfterSelf(rowElement);
  282. }
  283. }
  284. else
  285. { //there are no other rows already defined at sheetData
  286. //Add a new row elemento to sheetData
  287. worksheetXDocument.Root.Element(S.sheetData).Add(rowElement);
  288. }
  289. //Add the new cell to the row Element
  290. rowElement.Add(newCell);
  291. }
  292. else
  293. {
  294. //row containing the cell to set the value to is already defined at sheetData
  295. //look if cell already exist at that row
  296. XElement currentCell = rowElement
  297. .Elements(S.c)
  298. .Where(t => t.Attribute(NoNamespace.r).Value == cellReference)
  299. .FirstOrDefault();
  300. if (currentCell == null)
  301. { //cell element does not exist at row indicated as parameter
  302. //find the inmediate right column for the cell to set the value to
  303. XElement columnAfterXElement = FindColumAfter(worksheetXDocument, row, column);
  304. if (columnAfterXElement != null)
  305. {
  306. //Insert the new cell before the inmediate right column
  307. columnAfterXElement.AddBeforeSelf(newCell);
  308. }
  309. else
  310. { //There is no inmediate right cell
  311. //Add the new cell as the last element for the row
  312. rowElement.Add(newCell);
  313. }
  314. }
  315. else
  316. {
  317. //cell alreay exist
  318. //replace the current cell with that with the new value
  319. currentCell.ReplaceWith(newCell);
  320. }
  321. }
  322. }
  323. // Finds the row element (r) with a higher number than the specified "row" number
  324. private static XElement FindRowAfter(XDocument worksheet, int row)
  325. {
  326. return worksheet.Root
  327. .Element(S.sheetData)
  328. .Elements(S.row)
  329. .FirstOrDefault(r => System.Convert.ToInt32(r.Attribute(NoNamespace.r).Value) > row);
  330. }
  331. // Finds the cell element (c) in the specified row that is after the specified "column" number
  332. private static XElement FindColumAfter(XDocument worksheet, int row, int column)
  333. {
  334. return worksheet.Root
  335. .Element(S.sheetData)
  336. .Elements(S.row)
  337. .FirstOrDefault(r => System.Convert.ToInt32(r.Attribute(NoNamespace.r).Value) == row)
  338. .Elements(S.c)
  339. .FirstOrDefault(c => GetColumnNumber(c.Attribute(NoNamespace.r).Value) > GetColumnNumber(GetColumnId(column) + row));
  340. }
  341. // Converts the column reference string to a column number (e.g. A -> 1, B -> 2)
  342. public static int GetColumnNumber(string cellReference)
  343. {
  344. int columnNumber = 0;
  345. foreach (char c in cellReference)
  346. {
  347. if (Char.IsLetter(c))
  348. columnNumber = columnNumber * 26 + System.Convert.ToInt32(c) - System.Convert.ToInt32('A') + 1;
  349. }
  350. return columnNumber;
  351. }
  352. // Converts a cell reference string into the row and column numbers for that cell
  353. // e.g. G5 -> [row = 5, column = 7]
  354. private static void GetRowColumn(string cellReference, out int row, out int column)
  355. {
  356. row = 0;
  357. column = 0;
  358. foreach (char c in cellReference)
  359. {
  360. if (Char.IsLetter(c))
  361. column = column * 26 + System.Convert.ToInt32(c) - System.Convert.ToInt32('A') + 1;
  362. else
  363. row = row * 10 + System.Convert.ToInt32(c) - System.Convert.ToInt32('0');
  364. }
  365. }
  366. // Returns the row and column numbers and worksheet part for the named range
  367. public static WorksheetPart GetRange(SpreadsheetDocument doc, string rangeName, out int startRow, out int startColumn, out int endRow, out int endColumn)
  368. {
  369. XDocument book = doc.WorkbookPart.GetXDocument();
  370. if (book.Root.Element(S.definedNames) == null)
  371. throw new ArgumentException("Range name not found: " + rangeName);
  372. XElement element = book.Root.Element(S.definedNames).Elements(S.definedName)
  373. .Where(t => t.Attribute(NoNamespace.name).Value == rangeName).FirstOrDefault();
  374. if (element == null)
  375. throw new ArgumentException("Range name not found: " + rangeName);
  376. string sheetName = element.Value.Substring(0, element.Value.IndexOf('!'));
  377. string range = element.Value.Substring(element.Value.IndexOf('!') + 1).Replace("$","");
  378. int colonIndex = range.IndexOf(':');
  379. GetRowColumn(range.Substring(0, colonIndex), out startRow, out startColumn);
  380. GetRowColumn(range.Substring(colonIndex + 1), out endRow, out endColumn);
  381. return GetWorksheet(doc, sheetName);
  382. }
  383. // Sets the named range with the specified range of row and column numbers
  384. public static void SetRange(SpreadsheetDocument doc, string rangeName, string sheetName, int startRow, int startColumn, int endRow, int endColumn)
  385. {
  386. XDocument book = doc.WorkbookPart.GetXDocument();
  387. if (book.Root.Element(S.definedNames) == null)
  388. book.Root.Add(new XElement(S.definedNames));
  389. XElement element = book.Root.Element(S.definedNames).Elements(S.definedName)
  390. .Where(t => t.Attribute(NoNamespace.name).Value == rangeName).FirstOrDefault();
  391. if (element == null)
  392. {
  393. element = new XElement(S.definedName, new XAttribute(NoNamespace.name, rangeName));
  394. book.Root.Element(S.definedNames).Add(element);
  395. }
  396. element.SetValue(String.Format("{0}!${1}${2}:${3}${4}", sheetName, GetColumnId(startColumn), startRow, GetColumnId(endColumn), endRow));
  397. doc.WorkbookPart.PutXDocument();
  398. }
  399. // Sets the end row for the named range
  400. public static void UpdateRangeEndRow(SpreadsheetDocument doc, string rangeName, int lastRow)
  401. {
  402. // Update named range used by pivot table
  403. XDocument book = doc.WorkbookPart.GetXDocument();
  404. XElement element = book.Root.Element(S.definedNames).Elements(S.definedName)
  405. .Where(t => t.Attribute(NoNamespace.name).Value == rangeName).FirstOrDefault();
  406. if (element != null)
  407. {
  408. string original = element.Value;
  409. element.SetValue(original.Substring(0, original.Length - 1) + lastRow.ToString());
  410. }
  411. doc.WorkbookPart.PutXDocument();
  412. }
  413. // Creates an empty row element (r) with the specified row number
  414. private static XElement CreateEmptyRow(int row)
  415. {
  416. return new XElement(S.row, new XAttribute(NoNamespace.r, row.ToString()));
  417. }
  418. public static void ForceCalculateOnLoad(SpreadsheetDocument document)
  419. {
  420. XDocument book = document.WorkbookPart.GetXDocument();
  421. XElement element = book.Root.Element(S.calcPr);
  422. if (element == null)
  423. {
  424. book.Root.Add(new XElement(S.calcPr));
  425. }
  426. element.SetAttributeValue(NoNamespace.fullCalcOnLoad, "1");
  427. document.WorkbookPart.PutXDocument();
  428. }
  429. public static void FormulaReplaceSheetName(SpreadsheetDocument document, string oldName, string newName)
  430. {
  431. foreach (WorksheetPart sheetPart in document.WorkbookPart.WorksheetParts)
  432. {
  433. XDocument sheetDoc = sheetPart.GetXDocument();
  434. bool changed = false;
  435. foreach (XElement formula in sheetDoc.Descendants(S.f))
  436. {
  437. ParseFormula parser = new ParseFormula(formula.Value);
  438. string newFormula = parser.ReplaceSheetName(oldName, newName);
  439. if (newFormula != formula.Value)
  440. {
  441. formula.SetValue(newFormula);
  442. changed = true;
  443. }
  444. }
  445. if (changed)
  446. {
  447. sheetPart.PutXDocument();
  448. ForceCalculateOnLoad(document);
  449. }
  450. }
  451. }
  452. // Copy all cells in the specified range to a new location
  453. public static void CopyCellRange(SpreadsheetDocument document, WorksheetPart worksheet, int startRow, int startColumn, int endRow, int endColumn,
  454. int toRow, int toColumn)
  455. {
  456. int rowOffset = toRow - startRow;
  457. int columnOffset = toColumn - startColumn;
  458. XDocument worksheetXDocument = worksheet.GetXDocument();
  459. for (int row = startRow; row <= endRow; row++)
  460. for (int column = startColumn; column <= endColumn; column++)
  461. {
  462. XElement oldCell = GetCell(worksheetXDocument, column, row);
  463. if (oldCell != null)
  464. {
  465. XElement newCell = new XElement(oldCell);
  466. newCell.SetAttributeValue(NoNamespace.r, GetColumnId(column + columnOffset) + (row + rowOffset).ToString());
  467. XElement formula = newCell.Element(S.f);
  468. if (formula != null)
  469. {
  470. ParseFormula parser = new ParseFormula(formula.Value);
  471. formula.SetValue(parser.ReplaceRelativeCell(rowOffset, columnOffset));
  472. }
  473. SetCell(worksheetXDocument, newCell);
  474. }
  475. }
  476. worksheet.PutXDocument();
  477. ForceCalculateOnLoad(document);
  478. }
  479. // Creates a pivot table in the specified sheet using the specified range name
  480. // The new pivot table will not be configured with any fields in the rows, columns, filters or values
  481. public static PivotTablePart CreatePivotTable(SpreadsheetDocument document, string rangeName, WorksheetPart sheet)
  482. {
  483. int startRow, startColumn, endRow, endColumn;
  484. WorksheetPart sourceSheet = GetRange(document, rangeName, out startRow, out startColumn, out endRow, out endColumn);
  485. // Fill out pivotFields element (for PivotTablePart) and cacheFields element (for PivotTableCacheDefinitionPart)
  486. // with an element for each column in the source range
  487. XElement pivotFields = new XElement(S.pivotFields, new XAttribute(NoNamespace.count, (endColumn - startColumn + 1).ToString()));
  488. XElement cacheFields = new XElement(S.cacheFields, new XAttribute(NoNamespace.count, (endColumn - startColumn + 1).ToString()));
  489. for (int column = startColumn; column <= endColumn; column++)
  490. {
  491. pivotFields.Add(new XElement(S.pivotField, new XAttribute(NoNamespace.showAll, "0")));
  492. XElement sharedItems = new XElement(S.sharedItems);
  493. // Determine numeric sharedItems values, if any
  494. object value = GetCellValue(document, sourceSheet, column, startRow + 1);
  495. if (value is double || value is Int32)
  496. {
  497. bool hasDouble = false;
  498. double minValue = Convert.ToDouble(value);
  499. double maxValue = Convert.ToDouble(value);
  500. if (value is double)
  501. hasDouble = true;
  502. for (int row = startRow + 1; row <= endRow; row++)
  503. {
  504. value = GetCellValue(document, sourceSheet, column, row);
  505. if (value is double)
  506. hasDouble = true;
  507. if (Convert.ToDouble(value) < minValue)
  508. minValue = Convert.ToDouble(value);
  509. if (Convert.ToDouble(value) > maxValue)
  510. maxValue = Convert.ToDouble(value);
  511. }
  512. sharedItems.Add(new XAttribute(NoNamespace.containsSemiMixedTypes, "0"),
  513. new XAttribute(NoNamespace.containsString, "0"), new XAttribute(NoNamespace.containsNumber, "1"),
  514. new XAttribute(NoNamespace.minValue, minValue.ToString()), new XAttribute(NoNamespace.maxValue, maxValue.ToString()));
  515. if (!hasDouble)
  516. sharedItems.Add(new XAttribute(NoNamespace.containsInteger, "1"));
  517. }
  518. cacheFields.Add(new XElement(S.cacheField, new XAttribute(NoNamespace.name, GetCellValue(document, sourceSheet, column, startRow).ToString()),
  519. new XAttribute(NoNamespace.numFmtId, "0"), sharedItems));
  520. }
  521. // Fill out pivotCacheRecords element (for PivotTableCacheRecordsPart) with an element
  522. // for each row in the source range
  523. XElement pivotCacheRecords = new XElement(S.pivotCacheRecords, new XAttribute("xmlns", S.s),
  524. new XAttribute(XNamespace.Xmlns + "r", R.r), new XAttribute(NoNamespace.count, (endRow - startRow).ToString()));
  525. for (int row = startRow + 1; row <= endRow; row++)
  526. {
  527. XElement r = new XElement(S.r);
  528. // Fill the record element with a value from each column in the source row
  529. for (int column = startColumn; column <= endColumn; column++)
  530. {
  531. object value = GetCellValue(document, sourceSheet, column, row);
  532. if (value is String)
  533. r.Add(new XElement(S._s, new XAttribute(NoNamespace.v, value.ToString())));
  534. else
  535. r.Add(new XElement(S.n, new XAttribute(NoNamespace.v, value.ToString())));
  536. }
  537. pivotCacheRecords.Add(r);
  538. }
  539. // Create pivot table parts with proper links
  540. PivotTablePart pivotTable = sheet.AddNewPart<PivotTablePart>();
  541. PivotTableCacheDefinitionPart cacheDef = pivotTable.AddNewPart<PivotTableCacheDefinitionPart>();
  542. PivotTableCacheRecordsPart records = cacheDef.AddNewPart<PivotTableCacheRecordsPart>();
  543. document.WorkbookPart.AddPart<PivotTableCacheDefinitionPart>(cacheDef);
  544. // Set content for the PivotTableCacheRecordsPart and PivotTableCacheDefinitionPart
  545. records.PutXDocument(new XDocument(pivotCacheRecords));
  546. cacheDef.PutXDocument(new XDocument(new XElement(S.pivotCacheDefinition, new XAttribute("xmlns", S.s),
  547. new XAttribute(XNamespace.Xmlns + "r", R.r), new XAttribute(R.id, cacheDef.GetIdOfPart(records)),
  548. new XAttribute(NoNamespace.recordCount, (endRow - startRow).ToString()),
  549. new XElement(S.cacheSource, new XAttribute(NoNamespace.type, "worksheet"),
  550. new XElement(S.worksheetSource, new XAttribute(NoNamespace.name, rangeName))),
  551. cacheFields)));
  552. // Create the pivotCache entry in the workbook part
  553. int cacheId = 1;
  554. XDocument wb = document.WorkbookPart.GetXDocument();
  555. if (wb.Root.Element(S.pivotCaches) == null)
  556. wb.Root.Add(new XElement(S.pivotCaches));
  557. else
  558. {
  559. if (wb.Root.Element(S.pivotCaches).Elements(S.pivotCache).Count() != 0)
  560. cacheId = wb.Root.Element(S.pivotCaches).Elements(S.pivotCache).Max(n => Convert.ToInt32(n.Attribute(NoNamespace.cacheId).Value)) + 1;
  561. }
  562. wb.Root.Element(S.pivotCaches).Add(new XElement(S.pivotCache,
  563. new XAttribute(NoNamespace.cacheId, cacheId),
  564. new XAttribute(R.id, document.WorkbookPart.GetIdOfPart(cacheDef))));
  565. document.WorkbookPart.PutXDocument();
  566. // Set the content for the PivotTablePart
  567. pivotTable.PutXDocument(new XDocument(new XElement(S.pivotTableDefinition, new XAttribute("xmlns", S.s),
  568. new XAttribute(NoNamespace.name, "PivotTable1"), new XAttribute(NoNamespace.cacheId, cacheId.ToString()),
  569. new XAttribute(NoNamespace.dataCaption, "Values"),
  570. new XElement(S.location, new XAttribute(NoNamespace._ref, "A3:C20"),
  571. new XAttribute(NoNamespace.firstHeaderRow, "1"), new XAttribute(NoNamespace.firstDataRow, "1"),
  572. new XAttribute(NoNamespace.firstDataCol, "0")), pivotFields)));
  573. return pivotTable;
  574. }
  575. public enum PivotAxis { Row, Column, Page };
  576. public static void AddPivotAxis(SpreadsheetDocument document, WorksheetPart sheet, string fieldName, PivotAxis axis)
  577. {
  578. // Create indexed items in cache and definition
  579. PivotTablePart pivotTablePart = sheet.GetPartsOfType<PivotTablePart>().First();
  580. PivotTableCacheDefinitionPart cacheDefPart = pivotTablePart.GetPartsOfType<PivotTableCacheDefinitionPart>().First();
  581. PivotTableCacheRecordsPart recordsPart = cacheDefPart.GetPartsOfType<PivotTableCacheRecordsPart>().First();
  582. XDocument cacheDef = cacheDefPart.GetXDocument();
  583. int index = Array.FindIndex(cacheDef.Descendants(S.cacheField).ToArray(),
  584. z => z.Attribute(NoNamespace.name).Value == fieldName);
  585. XDocument records = recordsPart.GetXDocument();
  586. List<XElement> values = new List<XElement>();
  587. foreach (XElement rec in records.Descendants(S.r))
  588. {
  589. XElement val = rec.Elements().Skip(index).First();
  590. int x = Array.FindIndex(values.ToArray(), z => XElement.DeepEquals(z, val));
  591. if (x == -1)
  592. {
  593. values.Add(val);
  594. x = values.Count() - 1;
  595. }
  596. val.ReplaceWith(new XElement(S.x, new XAttribute(NoNamespace.v, x)));
  597. }
  598. XElement sharedItems = cacheDef.Descendants(S.cacheField).Skip(index).First().Element(S.sharedItems);
  599. sharedItems.Add(new XAttribute(NoNamespace.count, values.Count()), values);
  600. recordsPart.PutXDocument();
  601. cacheDefPart.PutXDocument();
  602. // Add axis definition to pivot table field
  603. XDocument pivotTable = pivotTablePart.GetXDocument();
  604. XElement pivotField = pivotTable.Descendants(S.pivotField).Skip(index).First();
  605. XElement items = new XElement(S.items, new XAttribute(NoNamespace.count, values.Count() + 1),
  606. values.OrderBy(z => z.Attribute(NoNamespace.v).Value).Select(z => new XElement(S.item,
  607. new XAttribute(NoNamespace.x, Array.FindIndex(values.ToArray(),
  608. a => a.Attribute(NoNamespace.v).Value == z.Attribute(NoNamespace.v).Value)))));
  609. items.Add(new XElement(S.item, new XAttribute(NoNamespace.t, "default")));
  610. switch (axis)
  611. {
  612. case PivotAxis.Column:
  613. pivotField.Add(new XAttribute(NoNamespace.axis, "axisCol"), items);
  614. // Add to colFields
  615. {
  616. XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields);
  617. if (fields == null)
  618. {
  619. fields = new XElement(S.colFields, new XAttribute(NoNamespace.count, 0));
  620. XElement rowFields = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields);
  621. if (rowFields == null)
  622. pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields);
  623. else
  624. rowFields.AddAfterSelf(fields);
  625. }
  626. fields.Add(new XElement(S.field, new XAttribute(NoNamespace.x, index)));
  627. fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString();
  628. }
  629. break;
  630. case PivotAxis.Row:
  631. pivotField.Add(new XAttribute(NoNamespace.axis, "axisRow"), items);
  632. // Add to rowFields
  633. {
  634. XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields);
  635. if (fields == null)
  636. {
  637. fields = new XElement(S.rowFields, new XAttribute(NoNamespace.count, 0));
  638. pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields);
  639. }
  640. fields.Add(new XElement(S.field, new XAttribute(NoNamespace.x, index)));
  641. fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString();
  642. }
  643. break;
  644. case PivotAxis.Page:
  645. pivotField.Add(new XAttribute(NoNamespace.axis, "axisPage"), items);
  646. // Add to pageFields
  647. {
  648. XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.pageFields);
  649. if (fields == null)
  650. {
  651. fields = new XElement(S.pageFields, new XAttribute(NoNamespace.count, 0));
  652. XElement prev = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields);
  653. if (prev == null)
  654. prev = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields);
  655. if (prev == null)
  656. pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields);
  657. else
  658. prev.AddAfterSelf(fields);
  659. }
  660. fields.Add(new XElement(S.pageField, new XAttribute(NoNamespace.fld, index)));
  661. fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString();
  662. }
  663. break;
  664. }
  665. pivotTablePart.PutXDocument();
  666. ForcePivotRefresh(cacheDefPart);
  667. }
  668. public static void AddDataValueLabel(SpreadsheetDocument document, WorksheetPart sheet, PivotAxis axis)
  669. {
  670. PivotTablePart pivotTablePart = sheet.GetPartsOfType<PivotTablePart>().First();
  671. XDocument pivotTable = pivotTablePart.GetXDocument();
  672. switch (axis)
  673. {
  674. case PivotAxis.Column:
  675. // Add to colFields
  676. {
  677. XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields);
  678. if (fields == null)
  679. {
  680. fields = new XElement(S.colFields, new XAttribute(NoNamespace.count, 0));
  681. XElement rowFields = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields);
  682. if (rowFields == null)
  683. pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields);
  684. else
  685. rowFields.AddAfterSelf(fields);
  686. }
  687. fields.Add(new XElement(S.field, new XAttribute(NoNamespace.x, -2)));
  688. fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString();
  689. }
  690. break;
  691. case PivotAxis.Row:
  692. // Add to rowFields
  693. {
  694. XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields);
  695. if (fields == null)
  696. {
  697. fields = new XElement(S.rowFields, new XAttribute(NoNamespace.count, 0));
  698. pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields);
  699. }
  700. fields.Add(new XElement(S.field, new XAttribute(NoNamespace.x, -2)));
  701. fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString();
  702. }
  703. break;
  704. case PivotAxis.Page:
  705. // Add to pageFields
  706. {
  707. XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.pageFields);
  708. if (fields == null)
  709. {
  710. fields = new XElement(S.pageFields, new XAttribute(NoNamespace.count, 0));
  711. XElement prev = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields);
  712. if (prev == null)
  713. prev = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields);
  714. if (prev == null)
  715. pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields).AddAfterSelf(fields);
  716. else
  717. prev.AddAfterSelf(fields);
  718. }
  719. fields.Add(new XElement(S.pageField, new XAttribute(NoNamespace.fld, -2)));
  720. fields.Attribute(NoNamespace.count).Value = fields.Elements(S.field).Count().ToString();
  721. }
  722. break;
  723. }
  724. pivotTablePart.PutXDocument();
  725. PivotTableCacheDefinitionPart cacheDefPart = pivotTablePart.GetPartsOfType<PivotTableCacheDefinitionPart>().First();
  726. ForcePivotRefresh(cacheDefPart);
  727. }
  728. public static void AddDataValue(SpreadsheetDocument document, WorksheetPart sheet, string fieldName)
  729. {
  730. PivotTablePart pivotTablePart = sheet.GetPartsOfType<PivotTablePart>().First();
  731. PivotTableCacheDefinitionPart cacheDefPart = pivotTablePart.GetPartsOfType<PivotTableCacheDefinitionPart>().First();
  732. XDocument cacheDef = cacheDefPart.GetXDocument();
  733. int index = Array.FindIndex(cacheDef.Descendants(S.cacheField).ToArray(),
  734. z => z.Attribute(NoNamespace.name).Value == fieldName);
  735. XDocument pivotTable = pivotTablePart.GetXDocument();
  736. XElement pivotField = pivotTable.Descendants(S.pivotField).Skip(index).First();
  737. pivotField.Add(new XAttribute(NoNamespace.dataField, "1"));
  738. XElement fields = pivotTable.Element(S.pivotTableDefinition).Element(S.dataFields);
  739. if (fields == null)
  740. {
  741. fields = new XElement(S.dataFields, new XAttribute(NoNamespace.count, 0));
  742. XElement prev = pivotTable.Element(S.pivotTableDefinition).Element(S.pageFields);
  743. if (prev == null)
  744. prev = pivotTable.Element(S.pivotTableDefinition).Element(S.colFields);
  745. if (prev == null)
  746. prev = pivotTable.Element(S.pivotTableDefinition).Element(S.rowFields);
  747. if (prev == null)
  748. prev = pivotTable.Element(S.pivotTableDefinition).Element(S.pivotFields);
  749. prev.AddAfterSelf(fields);
  750. }
  751. fields.Add(new XElement(S.dataField, new XAttribute(NoNamespace.name, "Sum of " + fieldName),
  752. new XAttribute(NoNamespace.fld, index), new XAttribute(NoNamespace.baseField, 0),
  753. new XAttribute(NoNamespace.baseItem, 0)));
  754. int count = fields.Elements(S.dataField).Count();
  755. fields.Attribute(NoNamespace.count).Value = count.ToString();
  756. if (count == 2)
  757. { // Only when data field count goes from 1 to 2 do we add a special column to label the data fields
  758. AddDataValueLabel(document, sheet, PivotAxis.Column);
  759. }
  760. pivotTablePart.PutXDocument();
  761. ForcePivotRefresh(cacheDefPart);
  762. }
  763. private static void ForcePivotRefresh(PivotTableCacheDefinitionPart cacheDef)
  764. {
  765. XDocument doc = cacheDef.GetXDocument();
  766. XElement def = doc.Element(S.pivotCacheDefinition);
  767. if (def.Attribute(NoNamespace.refreshOnLoad) == null)
  768. def.Add(new XAttribute(NoNamespace.refreshOnLoad, 1));
  769. else
  770. def.Attribute(NoNamespace.refreshOnLoad).Value = "1";
  771. cacheDef.PutXDocument();
  772. }
  773. public static void CheckNumberFormat(SpreadsheetDocument document, int fmtID, string formatCode)
  774. {
  775. XElement numFmt = new XElement(S.numFmt, new XAttribute(NoNamespace.numFmtId, fmtID.ToString()),
  776. new XAttribute(NoNamespace.formatCode, formatCode));
  777. XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument();
  778. XElement numFmts = styles.Root.Element(S.numFmts);
  779. if (numFmts == null)
  780. {
  781. styles.Root.Element(S.fonts).AddBeforeSelf(new XElement(S.numFmts, new XAttribute(NoNamespace.count, "0")));
  782. numFmts = styles.Root.Element(S.numFmts);
  783. }
  784. int index = Array.FindIndex(numFmts.Elements(S.numFmt).ToArray(),
  785. z => XElement.DeepEquals(z, numFmt));
  786. if (index == -1)
  787. {
  788. numFmts.Add(numFmt);
  789. numFmts.Attribute(NoNamespace.count).Value = numFmts.Elements(S.numFmt).Count().ToString();
  790. document.WorkbookPart.WorkbookStylesPart.PutXDocument();
  791. }
  792. }
  793. public class ColorInfo
  794. {
  795. public enum ColorType { Theme, Indexed };
  796. private bool Auto;
  797. private string RGB;
  798. private int Indexed;
  799. private int Theme;
  800. private double Tint;
  801. public ColorInfo()
  802. {
  803. Auto = true;
  804. }
  805. public ColorInfo(ColorType type, int value)
  806. {
  807. if (type == ColorType.Indexed)
  808. Indexed = value;
  809. else if (type == ColorType.Theme)
  810. Theme = value;
  811. }
  812. public ColorInfo(int theme, double tint)
  813. {
  814. Theme = theme;
  815. Tint = tint;
  816. }
  817. public ColorInfo(string rgb)
  818. {
  819. RGB = rgb;
  820. }
  821. public XElement GetXElement(XName colorName)
  822. {
  823. XElement color = new XElement(colorName);
  824. if (Auto)
  825. color.Add(new XAttribute(NoNamespace.auto, "1"));
  826. else if (RGB != null)
  827. color.Add(new XAttribute(NoNamespace.rgb, RGB));
  828. else if (Indexed != 0)
  829. color.Add(new XAttribute(NoNamespace.indexed, Indexed));
  830. else
  831. color.Add(new XAttribute(NoNamespace.theme, Theme));
  832. if (Tint != 0)
  833. color.Add(new XAttribute(NoNamespace.tint, Tint));
  834. return color;
  835. }
  836. }
  837. public class Font
  838. {
  839. public enum SchemeType { None, Major, Minor };
  840. public bool Bold { get; set; }
  841. public ColorInfo Color { get; set; }
  842. public bool Condense { get; set; }
  843. public bool Extend { get; set; }
  844. public int Family { get; set; }
  845. public bool Italic { get; set; }
  846. public string Name { get; set; }
  847. public bool Outline { get; set; }
  848. public SchemeType Scheme { get; set; }
  849. public bool Shadow { get; set; }
  850. public bool StrikeThrough { get; set; }
  851. public int Size { get; set; }
  852. public bool Underline { get; set; }
  853. public XElement GetXElement()
  854. {
  855. XElement font = new XElement(S.font);
  856. if (Bold)
  857. font.Add(new XElement(S.b));
  858. if (Italic)
  859. font.Add(new XElement(S.i));
  860. if (Underline)
  861. font.Add(new XElement(S.u));
  862. if (StrikeThrough)
  863. font.Add(new XElement(S.strike));
  864. if (Condense)
  865. font.Add(new XElement(S.condense));
  866. if (Extend)
  867. font.Add(new XElement(S.extend));
  868. if (Outline)
  869. font.Add(new XElement(S.outline));
  870. if (Shadow)
  871. font.Add(new XElement(S.shadow));
  872. if (Size != 0)
  873. font.Add(new XElement(S.sz, new XAttribute(NoNamespace.val, Size.ToString())));
  874. if (Color != null)
  875. font.Add(Color.GetXElement(S.color));
  876. if (Name != null)
  877. font.Add(new XElement(S.name, new XAttribute(NoNamespace.val, Name)));
  878. if (Family != 0)
  879. font.Add(new XElement(S.family, new XAttribute(NoNamespace.val, Family.ToString())));
  880. switch (Scheme)
  881. {
  882. case SchemeType.Major:
  883. font.Add(new XElement(S.scheme, new XAttribute(NoNamespace.val, "major")));
  884. break;
  885. case SchemeType.Minor:
  886. font.Add(new XElement(S.scheme, new XAttribute(NoNamespace.val, "minor")));
  887. break;
  888. }
  889. return font;
  890. }
  891. }
  892. public static int GetFontIndex(SpreadsheetDocument document, Font f)
  893. {
  894. XElement font = f.GetXElement();
  895. XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument();
  896. XElement fonts = styles.Root.Element(S.fonts);
  897. int index = Array.FindIndex(fonts.Elements(S.font).ToArray(),
  898. z => XElement.DeepEquals(z, font));
  899. if (index != -1)
  900. return index;
  901. fonts.Add(font);
  902. fonts.Attribute(NoNamespace.count).Value = fonts.Elements(S.font).Count().ToString();
  903. document.WorkbookPart.WorkbookStylesPart.PutXDocument();
  904. return fonts.Elements(S.font).Count() - 1;
  905. }
  906. public class PatternFill
  907. {
  908. public enum PatternType
  909. {
  910. None, Solid, DarkDown, DarkGray, DarkGrid, DarkHorizontal, DarkTrellis, DarkUp, DarkVertical,
  911. Gray0625, Gray125, LightDown, LightGray, LightGrid, LightHorizontal, LightTrellis, LightUp, LightVertical, MediumGray
  912. };
  913. private PatternType Pattern;
  914. private ColorInfo BgColor;
  915. private ColorInfo FgColor;
  916. public PatternFill(PatternType pattern, ColorInfo bgColor, ColorInfo fgColor)
  917. {
  918. Pattern = pattern;
  919. BgColor = bgColor;
  920. FgColor = fgColor;
  921. }
  922. public XElement GetXElement()
  923. {
  924. XElement pattern = new XElement(S.patternFill);
  925. switch (Pattern)
  926. {
  927. case PatternType.DarkDown:
  928. pattern.Add(new XAttribute(NoNamespace.patternType, "darkDown"));
  929. break;
  930. case PatternType.DarkGray:
  931. pattern.Add(new XAttribute(NoNamespace.patternType, "darkGray"));
  932. break;
  933. case PatternType.DarkGrid:
  934. pattern.Add(new XAttribute(NoNamespace.patternType, "darkGrid"));
  935. break;
  936. case PatternType.DarkHorizontal:
  937. pattern.Add(new XAttribute(NoNamespace.patternType, "darkHorizontal"));
  938. break;
  939. case PatternType.DarkTrellis:
  940. pattern.Add(new XAttribute(NoNamespace.patternType, "darkTrellis"));
  941. break;
  942. case PatternType.DarkUp:
  943. pattern.Add(new XAttribute(NoNamespace.patternType, "darkUp"));
  944. break;
  945. case PatternType.DarkVertical:
  946. pattern.Add(new XAttribute(NoNamespace.patternType, "darkVertical"));
  947. break;
  948. case PatternType.Gray0625:
  949. pattern.Add(new XAttribute(NoNamespace.patternType, "gray0625"));
  950. break;
  951. case PatternType.Gray125:
  952. pattern.Add(new XAttribute(NoNamespace.patternType, "gray125"));
  953. break;
  954. case PatternType.LightDown:
  955. pattern.Add(new XAttribute(NoNamespace.patternType, "lightDown"));
  956. break;
  957. case PatternType.LightGray:
  958. pattern.Add(new XAttribute(NoNamespace.patternType, "lightGray"));
  959. break;
  960. case PatternType.LightGrid:
  961. pattern.Add(new XAttribute(NoNamespace.patternType, "lightGrid"));
  962. break;
  963. case PatternType.LightHorizontal:
  964. pattern.Add(new XAttribute(NoNamespace.patternType, "lightHorizontal"));
  965. break;
  966. case PatternType.LightTrellis:
  967. pattern.Add(new XAttribute(NoNamespace.patternType, "lightTrellis"));
  968. break;
  969. case PatternType.LightUp:
  970. pattern.Add(new XAttribute(NoNamespace.patternType, "lightUp"));
  971. break;
  972. case PatternType.LightVertical:
  973. pattern.Add(new XAttribute(NoNamespace.patternType, "lightVertical"));
  974. break;
  975. case PatternType.MediumGray:
  976. pattern.Add(new XAttribute(NoNamespace.patternType, "mediumGray"));
  977. break;
  978. case PatternType.None:
  979. pattern.Add(new XAttribute(NoNamespace.patternType, "none"));
  980. break;
  981. case PatternType.Solid:
  982. pattern.Add(new XAttribute(NoNamespace.patternType, "solid"));
  983. break;
  984. }
  985. if (FgColor != null)
  986. pattern.Add(FgColor.GetXElement(S.fgColor));
  987. if (BgColor != null)
  988. pattern.Add(BgColor.GetXElement(S.bgColor));
  989. return new XElement(S.fill, pattern);
  990. }
  991. }
  992. public class GradientStop
  993. {
  994. private double Position;
  995. private ColorInfo Color;
  996. public GradientStop(double position, ColorInfo color)
  997. {
  998. Position = position;
  999. Color = color;
  1000. }
  1001. public XElement GetXElement()
  1002. {
  1003. return new XElement(S.stop, new XAttribute(NoNamespace.position, Position), Color.GetXElement(S.color));
  1004. }
  1005. }
  1006. public class GradientFill
  1007. {
  1008. private bool PathGradient;
  1009. private int LinearDegree;
  1010. private double PathTop;
  1011. private double PathLeft;
  1012. private double PathBottom;
  1013. private double PathRight;
  1014. private List<GradientStop> Stops;
  1015. public GradientFill(int degree)
  1016. {
  1017. PathGradient = false;
  1018. LinearDegree = degree;
  1019. Stops = new List<GradientStop>();
  1020. }
  1021. public GradientFill(double top, double left, double bottom, double right)
  1022. {
  1023. PathGradient = true;
  1024. PathTop = top;
  1025. PathLeft = left;
  1026. PathBottom = bottom;
  1027. PathRight = right;
  1028. Stops = new List<GradientStop>();
  1029. }
  1030. public void AddStop(GradientStop stop)
  1031. {
  1032. Stops.Add(stop);
  1033. }
  1034. public XElement GetXElement()
  1035. {
  1036. XElement gradient = new XElement(S.gradientFill);
  1037. if (PathGradient)
  1038. {
  1039. gradient.Add(new XAttribute(NoNamespace.type, "path"),
  1040. new XAttribute(NoNamespace.left, PathLeft.ToString()), new XAttribute(NoNamespace.right, PathRight.ToString()),
  1041. new XAttribute(NoNamespace.top, PathTop.ToString()), new XAttribute(NoNamespace.bottom, PathBottom.ToString()));
  1042. }
  1043. else
  1044. {
  1045. gradient.Add(new XAttribute(NoNamespace.degree, LinearDegree.ToString()));
  1046. }
  1047. foreach (GradientStop stop in Stops)
  1048. gradient.Add(stop.GetXElement());
  1049. return new XElement(S.fill, gradient);
  1050. }
  1051. }
  1052. public static int GetFillIndex(SpreadsheetDocument document, PatternFill patternFill)
  1053. {
  1054. return GetFillIndex(document, patternFill.GetXElement());
  1055. }
  1056. public static int GetFillIndex(SpreadsheetDocument document, GradientFill gradientFill)
  1057. {
  1058. return GetFillIndex(document, gradientFill.GetXElement());
  1059. }
  1060. private static int GetFillIndex(SpreadsheetDocument document, XElement fill)
  1061. {
  1062. XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument();
  1063. XElement fills = styles.Root.Element(S.fills);
  1064. int index = Array.FindIndex(fills.Elements(S.fill).ToArray(),
  1065. z => XElement.DeepEquals(z, fill));
  1066. if (index != -1)
  1067. return index;
  1068. fills.Add(fill);
  1069. fills.Attribute(NoNamespace.count).Value = fills.Elements(S.fill).Count().ToString();
  1070. document.WorkbookPart.WorkbookStylesPart.PutXDocument();
  1071. return fills.Elements(S.fill).Count() - 1;
  1072. }
  1073. public class BorderLine
  1074. {
  1075. public enum LineStyle
  1076. {
  1077. None, DashDot, DashDotDot, Dashed, Dotted, Double, Hair,
  1078. Medium, MediumDashDot, MediumDashDotDot, MediumDashed, SlantDashDot, Thick, Thin
  1079. };
  1080. private LineStyle Style;
  1081. private ColorInfo Color;
  1082. public BorderLine(LineStyle style, ColorInfo color)
  1083. {
  1084. Style = style;
  1085. Color = color;
  1086. }
  1087. public XElement GetXElement(XName name)
  1088. {
  1089. XElement line = new XElement(name);
  1090. switch (Style)
  1091. {
  1092. case LineStyle.DashDot:
  1093. line.Add(new XAttribute(NoNamespace.style, "dashDot"));
  1094. break;
  1095. case LineStyle.DashDotDot:
  1096. line.Add(new XAttribute(NoNamespace.style, "dashDotDot"));
  1097. break;
  1098. case LineStyle.Dashed:
  1099. line.Add(new XAttribute(NoNamespace.style, "dashed"));
  1100. break;
  1101. case LineStyle.Dotted:
  1102. line.Add(new XAttribute(NoNamespace.style, "dotted"));
  1103. break;
  1104. case LineStyle.Double:
  1105. line.Add(new XAttribute(NoNamespace.style, "double"));
  1106. break;
  1107. case LineStyle.Hair:
  1108. line.Add(new XAttribute(NoNamespace.style, "hair"));
  1109. break;
  1110. case LineStyle.Medium:
  1111. line.Add(new XAttribute(NoNamespace.style, "medium"));
  1112. break;
  1113. case LineStyle.MediumDashDot:
  1114. line.Add(new XAttribute(NoNamespace.style, "mediumDashDot"));
  1115. break;
  1116. case LineStyle.MediumDashDotDot:
  1117. line.Add(new XAttribute(NoNamespace.style, "mediumDashDotDot"));
  1118. break;
  1119. case LineStyle.MediumDashed:
  1120. line.Add(new XAttribute(NoNamespace.style, "mediumDashed"));
  1121. break;
  1122. case LineStyle.SlantDashDot:
  1123. line.Add(new XAttribute(NoNamespace.style, "slantDashDot"));
  1124. break;
  1125. case LineStyle.Thick:
  1126. line.Add(new XAttribute(NoNamespace.style, "thick"));
  1127. break;
  1128. case LineStyle.Thin:
  1129. line.Add(new XAttribute(NoNamespace.style, "thin"));
  1130. break;
  1131. }
  1132. line.Add(Color.GetXElement(S.color));
  1133. return line;
  1134. }
  1135. }
  1136. public class Border
  1137. {
  1138. public BorderLine Top { get; set; }
  1139. public BorderLine Bottom { get; set; }
  1140. public BorderLine Left { get; set; }
  1141. public BorderLine Right { get; set; }
  1142. public BorderLine Horizontal { get; set; }
  1143. public BorderLine Vertical { get; set; }
  1144. public BorderLine Diagonal { get; set; }
  1145. public bool DiagonalDown { get; set; }
  1146. public bool DiagonalUp { get; set; }
  1147. public bool Outline { get; set; }
  1148. public XElement GetXElement()
  1149. {
  1150. XElement border = new XElement(S.border);
  1151. if (DiagonalDown)
  1152. border.Add(new XAttribute(NoNamespace.diagonalDown, "1"));
  1153. if (DiagonalUp)
  1154. border.Add(new XAttribute(NoNamespace.diagonalUp, "1"));
  1155. if (Outline)
  1156. border.Add(new XAttribute(NoNamespace.outline, "1"));
  1157. if (Left == null)
  1158. border.Add(new XElement(S.left));
  1159. else
  1160. border.Add(Left.GetXElement(S.left));
  1161. if (Right == null)
  1162. border.Add(new XElement(S.right));
  1163. else
  1164. border.Add(Right.GetXElement(S.right));
  1165. if (Top == null)
  1166. border.Add(new XElement(S.top));
  1167. else
  1168. border.Add(Top.GetXElement(S.top));
  1169. if (Bottom == null)
  1170. border.Add(new XElement(S.bottom));
  1171. else
  1172. border.Add(Bottom.GetXElement(S.bottom));
  1173. if (Diagonal == null)
  1174. border.Add(new XElement(S.diagonal));
  1175. else
  1176. border.Add(Diagonal.GetXElement(S.diagonal));
  1177. if (Horizontal != null)
  1178. border.Add(Horizontal.GetXElement(S.horizontal));
  1179. if (Vertical != null)
  1180. border.Add(Vertical.GetXElement(S.vertical));
  1181. return border;
  1182. }
  1183. }
  1184. public static int GetBorderIndex(SpreadsheetDocument document, Border b)
  1185. {
  1186. XElement border = b.GetXElement();
  1187. XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument();
  1188. XElement borders = styles.Root.Element(S.borders);
  1189. int index = Array.FindIndex(borders.Elements(S.border).ToArray(),
  1190. z => XElement.DeepEquals(z, border));
  1191. if (index != -1)
  1192. return index;
  1193. borders.Add(border);
  1194. borders.Attribute(NoNamespace.count).Value = borders.Elements(S.border).Count().ToString();
  1195. document.WorkbookPart.WorkbookStylesPart.PutXDocument();
  1196. return borders.Elements(S.border).Count() - 1;
  1197. }
  1198. public static int GetStyleIndex(SpreadsheetDocument document, string styleName)
  1199. {
  1200. XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument();
  1201. string xfId = styles.Root.Element(S.cellStyles).Elements(S.cellStyle)
  1202. .Where(t => t.Attribute(NoNamespace.name).Value == styleName)
  1203. .FirstOrDefault().Attribute(NoNamespace.xfId).Value;
  1204. XElement cellXfs = styles.Root.Element(S.cellXfs);
  1205. int index = Array.FindIndex(cellXfs.Elements(S.xf).ToArray(),
  1206. z => z.Attribute(NoNamespace.xfId).Value == xfId);
  1207. if (index != -1)
  1208. return index;
  1209. XElement cellStyleXf = styles.Root.Element(S.cellStyleXfs).Elements(S.xf).ToArray()[Convert.ToInt32(xfId)];
  1210. if (cellStyleXf != null)
  1211. { // Create new xf element under cellXfs
  1212. cellXfs.Add(new XElement(S.xf, new XAttribute(NoNamespace.numFmtId, cellStyleXf.Attribute(NoNamespace.numFmtId).Value),
  1213. new XAttribute(NoNamespace.fontId, cellStyleXf.Attribute(NoNamespace.fontId).Value),
  1214. new XAttribute(NoNamespace.fillId, cellStyleXf.Attribute(NoNamespace.fillId).Value),
  1215. new XAttribute(NoNamespace.borderId, cellStyleXf.Attribute(NoNamespace.borderId).Value),
  1216. new XAttribute(NoNamespace.xfId, xfId)));
  1217. cellXfs.Attribute(NoNamespace.count).Value = cellXfs.Elements(S.xf).Count().ToString();
  1218. document.WorkbookPart.WorkbookStylesPart.PutXDocument();
  1219. return cellXfs.Elements(S.xf).Count() - 1;
  1220. }
  1221. return 0;
  1222. }
  1223. public class CellAlignment
  1224. {
  1225. public enum Horizontal { General, Center, CenterContinuous, Distributed, Fill, Justify, Left, Right };
  1226. public enum Vertical { Bottom, Center, Distributed, Justify, Top };
  1227. public Horizontal HorizontalAlignment { get; set; }
  1228. public int Indent { get; set; }
  1229. public bool JustifyLastLine { get; set; }
  1230. public int ReadingOrder { get; set; }
  1231. public bool ShrinkToFit { get; set; }
  1232. public int TextRotation { get; set; }
  1233. public Vertical VerticalAlignment { get; set; }
  1234. public bool WrapText { get; set; }
  1235. public CellAlignment()
  1236. {
  1237. HorizontalAlignment = Horizontal.General;
  1238. Indent = 0;
  1239. JustifyLastLine = false;
  1240. ReadingOrder = 0;
  1241. ShrinkToFit = false;
  1242. TextRotation = 0;
  1243. VerticalAlignment = Vertical.Bottom;
  1244. WrapText = false;
  1245. }
  1246. public XElement GetXElement()
  1247. {
  1248. XElement align = new XElement(S.alignment);
  1249. switch (HorizontalAlignment)
  1250. {
  1251. case Horizontal.Center:
  1252. align.Add(new XAttribute(NoNamespace.horizontal, "center"));
  1253. break;
  1254. case Horizontal.CenterContinuous:
  1255. align.Add(new XAttribute(NoNamespace.horizontal, "centerContinuous"));
  1256. break;
  1257. case Horizontal.Distributed:
  1258. align.Add(new XAttribute(NoNamespace.horizontal, "distributed"));
  1259. break;
  1260. case Horizontal.Fill:
  1261. align.Add(new XAttribute(NoNamespace.horizontal, "fill"));
  1262. break;
  1263. case Horizontal.Justify:
  1264. align.Add(new XAttribute(NoNamespace.horizontal, "justify"));
  1265. break;
  1266. case Horizontal.Left:
  1267. align.Add(new XAttribute(NoNamespace.horizontal, "left"));
  1268. break;
  1269. case Horizontal.Right:
  1270. align.Add(new XAttribute(NoNamespace.horizontal, "right"));
  1271. break;
  1272. }
  1273. if (Indent != 0)
  1274. align.Add(new XAttribute(NoNamespace.indent, Indent));
  1275. if (JustifyLastLine)
  1276. align.Add(new XAttribute(NoNamespace.justifyLastLine, true));
  1277. if (ReadingOrder != 0)
  1278. align.Add(new XAttribute(NoNamespace.readingOrder, ReadingOrder));
  1279. if (ShrinkToFit)
  1280. align.Add(new XAttribute(NoNamespace.shrinkToFit, true));
  1281. if (TextRotation != 0)
  1282. align.Add(new XAttribute(NoNamespace.textRotation, TextRotation));
  1283. switch (VerticalAlignment)
  1284. {
  1285. case Vertical.Center:
  1286. align.Add(new XAttribute(NoNamespace.vertical, "center"));
  1287. break;
  1288. case Vertical.Distributed:
  1289. align.Add(new XAttribute(NoNamespace.vertical, "distributed"));
  1290. break;
  1291. case Vertical.Justify:
  1292. align.Add(new XAttribute(NoNamespace.vertical, "justify"));
  1293. break;
  1294. case Vertical.Top:
  1295. align.Add(new XAttribute(NoNamespace.vertical, "top"));
  1296. break;
  1297. }
  1298. if (WrapText)
  1299. align.Add(new XAttribute(NoNamespace.wrapText, true));
  1300. return align;
  1301. }
  1302. }
  1303. public static int GetStyleIndex(SpreadsheetDocument document, int numFmt, int font, int fill, int border, CellAlignment alignment, bool hidden, bool locked)
  1304. {
  1305. XElement xf = new XElement(S.xf, new XAttribute(NoNamespace.numFmtId, numFmt),
  1306. new XAttribute(NoNamespace.fontId, font), new XAttribute(NoNamespace.fillId, fill),
  1307. new XAttribute(NoNamespace.borderId, border), new XAttribute(NoNamespace.xfId, 0),
  1308. new XAttribute(NoNamespace.applyNumberFormat, (numFmt == 0) ? 0 : 1),
  1309. new XAttribute(NoNamespace.applyFont, (font == 0) ? 0 : 1),
  1310. new XAttribute(NoNamespace.applyFill, (fill == 0) ? 0 : 1),
  1311. new XAttribute(NoNamespace.applyBorder, (border == 0) ? 0 : 1));
  1312. if (alignment != null)
  1313. {
  1314. xf.Add(new XAttribute(NoNamespace.applyAlignment, "1"));
  1315. xf.Add(alignment.GetXElement());
  1316. }
  1317. else
  1318. xf.Add(new XAttribute(NoNamespace.applyAlignment, "0"));
  1319. if (hidden || locked)
  1320. {
  1321. XElement prot = new XElement(S.protection);
  1322. if (hidden)
  1323. prot.Add(new XAttribute(NoNamespace.hidden, true));
  1324. if (locked)
  1325. prot.Add(new XAttribute(NoNamespace.locked, true));
  1326. xf.Add(prot);
  1327. xf.Add(new XAttribute(NoNamespace.applyProtection, "1"));
  1328. }
  1329. else
  1330. xf.Add(new XAttribute(NoNamespace.applyProtection, "0"));
  1331. XDocument styles = document.WorkbookPart.WorkbookStylesPart.GetXDocument();
  1332. XElement cellXfs = styles.Root.Element(S.cellXfs);
  1333. int index = Array.FindIndex(cellXfs.Elements(S.xf).ToArray(),
  1334. z => XElement.DeepEquals(z, xf));
  1335. if (index != -1)
  1336. return index;
  1337. cellXfs.Add(xf);
  1338. cellXfs.Attribute(NoNamespace.count).Value = cellXfs.Elements(S.xf).Count().ToString();
  1339. document.WorkbookPart.WorkbookStylesPart.PutXDocument();
  1340. return cellXfs.Elements(S.xf).Count() - 1;
  1341. }
  1342. public static void CreateDefaultStyles(SpreadsheetDocument document)
  1343. {
  1344. // Create the style part
  1345. WorkbookStylesPart stylesPart = document.WorkbookPart.AddNewPart<WorkbookStylesPart>();
  1346. stylesPart.PutXDocument(new XDocument(XElement.Parse(
  1347. @"<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
  1348. <styleSheet xmlns='http://schemas.openxmlformats.org/spreadsheetml/2006/main'>
  1349. <fonts count='18'>
  1350. <font>
  1351. <sz val='11'/>
  1352. <color theme='1'/>
  1353. <name val='Calibri'/>
  1354. <family val='2'/>
  1355. <scheme val='minor'/>
  1356. </font>
  1357. <font>
  1358. <sz val='11'/>
  1359. <color theme='1'/>
  1360. <name val='Calibri'/>
  1361. <family val='2'/>
  1362. <scheme val='minor'/>
  1363. </font>
  1364. <font>
  1365. <b/>
  1366. <sz val='18'/>
  1367. <color theme='3'/>
  1368. <name val='Cambria'/>
  1369. <family val='2'/>
  1370. <scheme val='major'/>
  1371. </font>
  1372. <font>
  1373. <b/>
  1374. <sz val='15'/>
  1375. <color theme='3'/>
  1376. <name val='Calibri'/>
  1377. <family val='2'/>
  1378. <scheme val='minor'/>
  1379. </font>
  1380. <font>
  1381. <b/>
  1382. <sz val='13'/>
  1383. <color theme='3'/>
  1384. <name val='Calibri'/>
  1385. <family val='2'/>
  1386. <scheme val='minor'/>
  1387. </font>
  1388. <font>
  1389. <b/>
  1390. <sz val='11'/>
  1391. <color theme='3'/>
  1392. <name val='Calibri'/>
  1393. <family val='2'/>
  1394. <scheme val='minor'/>
  1395. </font>
  1396. <font>
  1397. <sz val='11'/>
  1398. <color rgb='FF006100'/>
  1399. <name val='Calibri'/>
  1400. <family val='2'/>
  1401. <scheme val='minor'/>
  1402. </font>
  1403. <font>
  1404. <sz val='11'/>
  1405. <color rgb='FF9C0006'/>
  1406. <name val='Calibri'/>
  1407. <family val='2'/>
  1408. <scheme val='minor'/>
  1409. </font>
  1410. <font>
  1411. <sz val='11'/>
  1412. <color rgb='FF9C6500'/>
  1413. <name val='Calibri'/>
  1414. <family val='2'/>
  1415. <scheme val='minor'/>
  1416. </font>
  1417. <font>
  1418. <sz val='11'/>
  1419. <color rgb='FF3F3F76'/>
  1420. <name val='Calibri'/>
  1421. <family val='2'/>
  1422. <scheme val='minor'/>
  1423. </font>
  1424. <font>
  1425. <b/>
  1426. <sz val='11'/>
  1427. <color rgb='FF3F3F3F'/>
  1428. <name val='Calibri'/>
  1429. <family val='2'/>
  1430. <scheme val='minor'/>
  1431. </font>
  1432. <font>
  1433. <b/>
  1434. <sz val='11'/>
  1435. <color rgb='FFFA7D00'/>
  1436. <name val='Calibri'/>
  1437. <family val='2'/>
  1438. <scheme val='minor'/>
  1439. </font>
  1440. <font>
  1441. <sz val='11'/>
  1442. <color rgb='FFFA7D00'/>
  1443. <name val='Calibri'/>
  1444. <family val='2'/>
  1445. <scheme val='minor'/>
  1446. </font>
  1447. <font>
  1448. <b/>
  1449. <sz val='11'/>
  1450. <color theme='0'/>
  1451. <name val='Calibri'/>
  1452. <family val='2'/>
  1453. <scheme val='minor'/>
  1454. </font>
  1455. <font>
  1456. <sz val='11'/>
  1457. <color rgb='FFFF0000'/>
  1458. <name val='Calibri'/>
  1459. <family val='2'/>
  1460. <scheme val='minor'/>
  1461. </font>
  1462. <font>
  1463. <i/>
  1464. <sz val='11'/>
  1465. <color rgb='FF7F7F7F'/>
  1466. <name val='Calibri'/>
  1467. <family val='2'/>
  1468. <scheme val='minor'/>
  1469. </font>
  1470. <font>
  1471. <b/>
  1472. <sz val='11'/>
  1473. <color theme='1'/>
  1474. <name val='Calibri'/>
  1475. <family val='2'/>
  1476. <scheme val='minor'/>
  1477. </font>
  1478. <font>
  1479. <sz val='11'/>
  1480. <color theme='0'/>
  1481. <name val='Calibri'/>
  1482. <family val='2'/>
  1483. <scheme val='minor'/>
  1484. </font>
  1485. </fonts>
  1486. <fills count='33'>
  1487. <fill>
  1488. <patternFill patternType='none'/>
  1489. </fill>
  1490. <fill>
  1491. <patternFill patternType='gray125'/>
  1492. </fill>
  1493. <fill>
  1494. <patternFill patternType='solid'>
  1495. <fgColor rgb='FFC6EFCE'/>
  1496. </patternFill>
  1497. </fill>
  1498. <fill>
  1499. <patternFill patternType='solid'>
  1500. <fgColor rgb='FFFFC7CE'/>
  1501. </patternFill>
  1502. </fill>
  1503. <fill>
  1504. <patternFill patternType='solid'>
  1505. <fgColor rgb='FFFFEB9C'/>
  1506. </patternFill>
  1507. </fill>
  1508. <fill>
  1509. <patternFill patternType='solid'>
  1510. <fgColor rgb='FFFFCC99'/>
  1511. </patternFill>
  1512. </fill>
  1513. <fill>
  1514. <patternFill patternType='solid'>
  1515. <fgColor rgb='FFF2F2F2'/>
  1516. </patternFill>
  1517. </fill>
  1518. <fill>
  1519. <patternFill patternType='solid'>
  1520. <fgColor rgb='FFA5A5A5'/>
  1521. </patternFill>
  1522. </fill>
  1523. <fill>
  1524. <patternFill patternType='solid'>
  1525. <fgColor rgb='FFFFFFCC'/>
  1526. </patternFill>
  1527. </fill>
  1528. <fill>
  1529. <patternFill patternType='solid'>
  1530. <fgColor theme='4'/>
  1531. </patternFill>
  1532. </fill>
  1533. <fill>
  1534. <patternFill patternType='solid'>
  1535. <fgColor theme='4' tint='0.79998168889431442'/>
  1536. <bgColor indexed='65'/>
  1537. </patternFill>
  1538. </fill>
  1539. <fill>
  1540. <patternFill patternType='solid'>
  1541. <fgColor theme='4' tint='0.59999389629810485'/>
  1542. <bgColor indexed='65'/>
  1543. </patternFill>
  1544. </fill>
  1545. <fill>
  1546. <patternFill patternType='solid'>
  1547. <fgColor theme='4' tint='0.39997558519241921'/>
  1548. <bgColor indexed='65'/>
  1549. </patternFill>
  1550. </fill>
  1551. <fill>
  1552. <patternFill patternType='solid'>
  1553. <fgColor theme='5'/>
  1554. </patternFill>
  1555. </fill>
  1556. <fill>
  1557. <patternFill patternType='solid'>
  1558. <fgColor theme='5' tint='0.79998168889431442'/>
  1559. <bgColor indexed='65'/>
  1560. </patternFill>
  1561. </fill>
  1562. <fill>
  1563. <patternFill patternType='solid'>
  1564. <fgColor theme='5' tint='0.59999389629810485'/>
  1565. <bgColor indexed='65'/>
  1566. </patternFill>
  1567. </fill>
  1568. <fill>
  1569. <patternFill patternType='solid'>
  1570. <fgColor theme='5' tint='0.39997558519241921'/>
  1571. <bgColor indexed='65'/>
  1572. </patternFill>
  1573. </fill>
  1574. <fill>
  1575. <patternFill patternType='solid'>
  1576. <fgColor theme='6'/>
  1577. </patternFill>
  1578. </fill>
  1579. <fill>
  1580. <patternFill patternType='solid'>
  1581. <fgColor theme='6' tint='0.79998168889431442'/>
  1582. <bgColor indexed='65'/>
  1583. </patternFill>
  1584. </fill>
  1585. <fill>
  1586. <patternFill patternType='solid'>
  1587. <fgColor theme='6' tint='0.59999389629810485'/>
  1588. <bgColor indexed='65'/>
  1589. </patternFill>
  1590. </fill>
  1591. <fill>
  1592. <patternFill patternType='solid'>
  1593. <fgColor theme='6' tint='0.39997558519241921'/>
  1594. <bgColor indexed='65'/>
  1595. </patternFill>
  1596. </fill>
  1597. <fill>
  1598. <patternFill patternType='solid'>
  1599. <fgColor theme='7'/>
  1600. </patternFill>
  1601. </fill>
  1602. <fill>
  1603. <patternFill patternType='solid'>
  1604. <fgColor theme='7' tint='0.79998168889431442'/>
  1605. <bgColor indexed='65'/>
  1606. </patternFill>
  1607. </fill>
  1608. <fill>
  1609. <patternFill patternType='solid'>
  1610. <fgColor theme='7' tint='0.59999389629810485'/>
  1611. <bgColor indexed='65'/>
  1612. </patternFill>
  1613. </fill>
  1614. <fill>
  1615. <patternFill patternType='solid'>
  1616. <fgColor theme='7' tint='0.39997558519241921'/>
  1617. <bgColor indexed='65'/>
  1618. </patternFill>
  1619. </fill>
  1620. <fill>
  1621. <patternFill patternType='solid'>
  1622. <fgColor theme='8'/>
  1623. </patternFill>
  1624. </fill>
  1625. <fill>
  1626. <patternFill patternType='solid'>
  1627. <fgColor theme='8' tint='0.79998168889431442'/>
  1628. <bgColor indexed='65'/>
  1629. </patternFill>
  1630. </fill>
  1631. <fill>
  1632. <patternFill patternType='solid'>
  1633. <fgColor theme='8' tint='0.59999389629810485'/>
  1634. <bgColor indexed='65'/>
  1635. </patternFill>
  1636. </fill>
  1637. <fill>
  1638. <patternFill patternType='solid'>
  1639. <fgColor theme='8' tint='0.39997558519241921'/>
  1640. <bgColor indexed='65'/>
  1641. </patternFill>
  1642. </fill>
  1643. <fill>
  1644. <patternFill patternType='solid'>
  1645. <fgColor theme='9'/>
  1646. </patternFill>
  1647. </fill>
  1648. <fill>
  1649. <patternFill patternType='solid'>
  1650. <fgColor theme='9' tint='0.79998168889431442'/>
  1651. <bgColor indexed='65'/>
  1652. </patternFill>
  1653. </fill>
  1654. <fill>
  1655. <patternFill patternType='solid'>
  1656. <fgColor theme='9' tint='0.59999389629810485'/>
  1657. <bgColor indexed='65'/>
  1658. </patternFill>
  1659. </fill>
  1660. <fill>
  1661. <patternFill patternType='solid'>
  1662. <fgColor theme='9' tint='0.39997558519241921'/>
  1663. <bgColor indexed='65'/>
  1664. </patternFill>
  1665. </fill>
  1666. </fills>
  1667. <borders count='10'>
  1668. <border>
  1669. <left/>
  1670. <right/>
  1671. <top/>
  1672. <bottom/>
  1673. <diagonal/>
  1674. </border>
  1675. <border>
  1676. <left/>
  1677. <right/>
  1678. <top/>
  1679. <bottom style='thick'>
  1680. <color theme='4'/>
  1681. </bottom>
  1682. <diagonal/>
  1683. </border>
  1684. <border>
  1685. <left/>
  1686. <right/>
  1687. <top/>
  1688. <bottom style='thick'>
  1689. <color theme='4' tint='0.499984740745262'/>
  1690. </bottom>
  1691. <diagonal/>
  1692. </border>
  1693. <border>
  1694. <left/>
  1695. <right/>
  1696. <top/>
  1697. <bottom style='medium'>
  1698. <color theme='4' tint='0.39997558519241921'/>
  1699. </bottom>
  1700. <diagonal/>
  1701. </border>
  1702. <border>
  1703. <left style='thin'>
  1704. <color rgb='FF7F7F7F'/>
  1705. </left>
  1706. <right style='thin'>
  1707. <color rgb='FF7F7F7F'/>
  1708. </right>
  1709. <top style='thin'>
  1710. <color rgb='FF7F7F7F'/>
  1711. </top>
  1712. <bottom style='thin'>
  1713. <color rgb='FF7F7F7F'/>
  1714. </bottom>
  1715. <diagonal/>
  1716. </border>
  1717. <border>
  1718. <left style='thin'>
  1719. <color rgb='FF3F3F3F'/>
  1720. </left>
  1721. <right style='thin'>
  1722. <color rgb='FF3F3F3F'/>
  1723. </right>
  1724. <top style='thin'>
  1725. <color rgb='FF3F3F3F'/>
  1726. </top>
  1727. <bottom style='thin'>
  1728. <color rgb='FF3F3F3F'/>
  1729. </bottom>
  1730. <diagonal/>
  1731. </border>
  1732. <border>
  1733. <left/>
  1734. <right/>
  1735. <top/>
  1736. <bottom style='double'>
  1737. <color rgb='FFFF8001'/>
  1738. </bottom>
  1739. <diagonal/>
  1740. </border>
  1741. <border>
  1742. <left style='double'>
  1743. <color rgb='FF3F3F3F'/>
  1744. </left>
  1745. <right style='double'>
  1746. <color rgb='FF3F3F3F'/>
  1747. </right>
  1748. <top style='double'>
  1749. <color rgb='FF3F3F3F'/>
  1750. </top>
  1751. <bottom style='double'>
  1752. <color rgb='FF3F3F3F'/>
  1753. </bottom>
  1754. <diagonal/>
  1755. </border>
  1756. <border>
  1757. <left style='thin'>
  1758. <color rgb='FFB2B2B2'/>
  1759. </left>
  1760. <right style='thin'>
  1761. <color rgb='FFB2B2B2'/>
  1762. </right>
  1763. <top style='thin'>
  1764. <color rgb='FFB2B2B2'/>
  1765. </top>
  1766. <bottom style='thin'>
  1767. <color rgb='FFB2B2B2'/>
  1768. </bottom>
  1769. <diagonal/>
  1770. </border>
  1771. <border>
  1772. <left/>
  1773. <right/>
  1774. <top style='thin'>
  1775. <color theme='4'/>
  1776. </top>
  1777. <bottom style='double'>
  1778. <color theme='4'/>
  1779. </bottom>
  1780. <diagonal/>
  1781. </border>
  1782. </borders>
  1783. <cellStyleXfs count='42'>
  1784. <xf numFmtId='0' fontId='0' fillId='0' borderId='0'/>
  1785. <xf numFmtId='0' fontId='2' fillId='0' borderId='0' applyNumberFormat='0' applyFill='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1786. <xf numFmtId='0' fontId='3' fillId='0' borderId='1' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/>
  1787. <xf numFmtId='0' fontId='4' fillId='0' borderId='2' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/>
  1788. <xf numFmtId='0' fontId='5' fillId='0' borderId='3' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/>
  1789. <xf numFmtId='0' fontId='5' fillId='0' borderId='0' applyNumberFormat='0' applyFill='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1790. <xf numFmtId='0' fontId='6' fillId='2' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1791. <xf numFmtId='0' fontId='7' fillId='3' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1792. <xf numFmtId='0' fontId='8' fillId='4' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1793. <xf numFmtId='0' fontId='9' fillId='5' borderId='4' applyNumberFormat='0' applyAlignment='0' applyProtection='0'/>
  1794. <xf numFmtId='0' fontId='10' fillId='6' borderId='5' applyNumberFormat='0' applyAlignment='0' applyProtection='0'/>
  1795. <xf numFmtId='0' fontId='11' fillId='6' borderId='4' applyNumberFormat='0' applyAlignment='0' applyProtection='0'/>
  1796. <xf numFmtId='0' fontId='12' fillId='0' borderId='6' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/>
  1797. <xf numFmtId='0' fontId='13' fillId='7' borderId='7' applyNumberFormat='0' applyAlignment='0' applyProtection='0'/>
  1798. <xf numFmtId='0' fontId='14' fillId='0' borderId='0' applyNumberFormat='0' applyFill='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1799. <xf numFmtId='0' fontId='1' fillId='8' borderId='8' applyNumberFormat='0' applyFont='0' applyAlignment='0' applyProtection='0'/>
  1800. <xf numFmtId='0' fontId='15' fillId='0' borderId='0' applyNumberFormat='0' applyFill='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1801. <xf numFmtId='0' fontId='16' fillId='0' borderId='9' applyNumberFormat='0' applyFill='0' applyAlignment='0' applyProtection='0'/>
  1802. <xf numFmtId='0' fontId='17' fillId='9' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1803. <xf numFmtId='0' fontId='1' fillId='10' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1804. <xf numFmtId='0' fontId='1' fillId='11' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1805. <xf numFmtId='0' fontId='17' fillId='12' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1806. <xf numFmtId='0' fontId='17' fillId='13' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1807. <xf numFmtId='0' fontId='1' fillId='14' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1808. <xf numFmtId='0' fontId='1' fillId='15' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1809. <xf numFmtId='0' fontId='17' fillId='16' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1810. <xf numFmtId='0' fontId='17' fillId='17' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1811. <xf numFmtId='0' fontId='1' fillId='18' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1812. <xf numFmtId='0' fontId='1' fillId='19' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1813. <xf numFmtId='0' fontId='17' fillId='20' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1814. <xf numFmtId='0' fontId='17' fillId='21' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1815. <xf numFmtId='0' fontId='1' fillId='22' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1816. <xf numFmtId='0' fontId='1' fillId='23' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1817. <xf numFmtId='0' fontId='17' fillId='24' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1818. <xf numFmtId='0' fontId='17' fillId='25' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1819. <xf numFmtId='0' fontId='1' fillId='26' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1820. <xf numFmtId='0' fontId='1' fillId='27' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1821. <xf numFmtId='0' fontId='17' fillId='28' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1822. <xf numFmtId='0' fontId='17' fillId='29' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1823. <xf numFmtId='0' fontId='1' fillId='30' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1824. <xf numFmtId='0' fontId='1' fillId='31' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1825. <xf numFmtId='0' fontId='17' fillId='32' borderId='0' applyNumberFormat='0' applyBorder='0' applyAlignment='0' applyProtection='0'/>
  1826. </cellStyleXfs>
  1827. <cellXfs count='1'>
  1828. <xf numFmtId='0' fontId='0' fillId='0' borderId='0' xfId='0'/>
  1829. </cellXfs>
  1830. <cellStyles count='42'>
  1831. <cellStyle name='20% - Accent1' xfId='19' builtinId='30' customBuiltin='1'/>
  1832. <cellStyle name='20% - Accent2' xfId='23' builtinId='34' customBuiltin='1'/>
  1833. <cellStyle name='20% - Accent3' xfId='27' builtinId='38' customBuiltin='1'/>
  1834. <cellStyle name='20% - Accent4' xfId='31' builtinId='42' customBuiltin='1'/>
  1835. <cellStyle name='20% - Accent5' xfId='35' builtinId='46' customBuiltin='1'/>
  1836. <cellStyle name='20% - Accent6' xfId='39' builtinId='50' customBuiltin='1'/>
  1837. <cellStyle name='40% - Accent1' xfId='20' builtinId='31' customBuiltin='1'/>
  1838. <cellStyle name='40% - Accent2' xfId='24' builtinId='35' customBuiltin='1'/>
  1839. <cellStyle name='40% - Accent3' xfId='28' builtinId='39' customBuiltin='1'/>
  1840. <cellStyle name='40% - Accent4' xfId='32' builtinId='43' customBuiltin='1'/>
  1841. <cellStyle name='40% - Accent5' xfId='36' builtinId='47' customBuiltin='1'/>
  1842. <cellStyle name='40% - Accent6' xfId='40' builtinId='51' customBuiltin='1'/>
  1843. <cellStyle name='60% - Accent1' xfId='21' builtinId='32' customBuiltin='1'/>
  1844. <cellStyle name='60% - Accent2' xfId='25' builtinId='36' customBuiltin='1'/>
  1845. <cellStyle name='60% - Accent3' xfId='29' builtinId='40' customBuiltin='1'/>
  1846. <cellStyle name='60% - Accent4' xfId='33' builtinId='44' customBuiltin='1'/>
  1847. <cellStyle name='60% - Accent5' xfId='37' builtinId='48' customBuiltin='1'/>
  1848. <cellStyle name='60% - Accent6' xfId='41' builtinId='52' customBuiltin='1'/>
  1849. <cellStyle name='Accent1' xfId='18' builtinId='29' customBuiltin='1'/>
  1850. <cellStyle name='Accent2' xfId='22' builtinId='33' customBuiltin='1'/>
  1851. <cellStyle name='Accent3' xfId='26' builtinId='37' customBuiltin='1'/>
  1852. <cellStyle name='Accent4' xfId='30' builtinId='41' customBuiltin='1'/>
  1853. <cellStyle name='Accent5' xfId='34' builtinId='45' customBuiltin='1'/>
  1854. <cellStyle name='Accent6' xfId='38' builtinId='49' customBuiltin='1'/>
  1855. <cellStyle name='Bad' xfId='7' builtinId='27' customBuiltin='1'/>
  1856. <cellStyle name='Calculation' xfId='11' builtinId='22' customBuiltin='1'/>
  1857. <cellStyle name='Check Cell' xfId='13' builtinId='23' customBuiltin='1'/>
  1858. <cellStyle name='Explanatory Text' xfId='16' builtinId='53' customBuiltin='1'/>
  1859. <cellStyle name='Good' xfId='6' builtinId='26' customBuiltin='1'/>
  1860. <cellStyle name='Heading 1' xfId='2' builtinId='16' customBuiltin='1'/>
  1861. <cellStyle name='Heading 2' xfId='3' builtinId='17' customBuiltin='1'/>
  1862. <cellStyle name='Heading 3' xfId='4' builtinId='18' customBuiltin='1'/>
  1863. <cellStyle name='Heading 4' xfId='5' builtinId='19' customBuiltin='1'/>
  1864. <cellStyle name='Input' xfId='9' builtinId='20' customBuiltin='1'/>
  1865. <cellStyle name='Linked Cell' xfId='12' builtinId='24' customBuiltin='1'/>
  1866. <cellStyle name='Neutral' xfId='8' builtinId='28' customBuiltin='1'/>
  1867. <cellStyle name='Normal' xfId='0' builtinId='0'/>
  1868. <cellStyle name='Note' xfId='15' builtinId='10' customBuiltin='1'/>
  1869. <cellStyle name='Output' xfId='10' builtinId='21' customBuiltin='1'/>
  1870. <cellStyle name='Title' xfId='1' builtinId='15' customBuiltin='1'/>
  1871. <cellStyle name='Total' xfId='17' builtinId='25' customBuiltin='1'/>
  1872. <cellStyle name='Warning Text' xfId='14' builtinId='11' customBuiltin='1'/>
  1873. </cellStyles>
  1874. <dxfs count='0'/>
  1875. <tableStyles count='0' defaultTableStyle='TableStyleMedium9' defaultPivotStyle='PivotStyleLight16'/>
  1876. </styleSheet>")));
  1877. }
  1878. /// <summary>
  1879. /// Creates a worksheet document and inserts data into it
  1880. /// </summary>
  1881. /// <param name="headerList">List of values that will act as the header</param>
  1882. /// <param name="valueTable">Values for worksheet content</param>
  1883. /// <param name="headerRow">Header row</param>
  1884. /// <returns></returns>
  1885. internal static WorksheetPart Create(SpreadsheetDocument document, List<string> headerList, string[][] valueTable, int headerRow)
  1886. {
  1887. XDocument xDocument = CreateEmptyWorksheet();
  1888. for (int i = 0; i < headerList.Count; i++)
  1889. {
  1890. AddValue(xDocument, headerRow, i + 1, headerList[i]);
  1891. }
  1892. int rows = valueTable.GetLength(0);
  1893. int cols = valueTable[0].GetLength(0);
  1894. for (int i = 0; i < rows; i++)
  1895. {
  1896. for (int j = 0; j < cols; j++)
  1897. {
  1898. AddValue(xDocument, i + headerRow + 1, j + 1, valueTable[i][j]);
  1899. }
  1900. }
  1901. WorksheetPart part = Add(document, xDocument);
  1902. return part;
  1903. }
  1904. /// <summary>
  1905. /// Creates element structure needed to describe an empty worksheet
  1906. /// </summary>
  1907. /// <returns>Document with contents for an empty worksheet</returns>
  1908. private static XDocument CreateEmptyWorksheet()
  1909. {
  1910. XDocument document =
  1911. new XDocument(
  1912. new XElement(ns + "worksheet",
  1913. new XAttribute("xmlns", ns),
  1914. new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
  1915. new XElement(ns + "sheetData")
  1916. )
  1917. );
  1918. return document;
  1919. }
  1920. /// <summary>
  1921. /// Adds a value to a cell inside a worksheet document
  1922. /// </summary>
  1923. /// <param name="worksheet">document to add values</param>
  1924. /// <param name="row">Row</param>
  1925. /// <param name="column">Column</param>
  1926. /// <param name="value">Value to add</param>
  1927. private static void AddValue(XDocument worksheet, int row, int column, string value)
  1928. {
  1929. //Set the cell reference
  1930. string cellReference = GetColumnId(column) + row.ToString();
  1931. double numericValue;
  1932. //Determining if value for cell is text or numeric
  1933. bool valueIsNumeric = double.TryParse(value, out numericValue);
  1934. //Creating the new cell element (markup)
  1935. XElement newCellXElement = valueIsNumeric ?
  1936. new XElement(ns + "c",
  1937. new XAttribute("r", cellReference),
  1938. new XElement(ns + "v", numericValue)
  1939. )
  1940. :
  1941. new XElement(ns + "c",
  1942. new XAttribute("r", cellReference),
  1943. new XAttribute("t", "inlineStr"),
  1944. new XElement(ns + "is",
  1945. new XElement(ns + "t", value)
  1946. )
  1947. );
  1948. // Find the row containing the cell to add the value to
  1949. XName rowName = "r";
  1950. XElement rowElement =
  1951. worksheet.Root
  1952. .Element(ns + "sheetData")
  1953. .Elements(ns + "row")
  1954. .Where(
  1955. t => t.Attribute(rowName).Value == row.ToString()
  1956. )
  1957. .FirstOrDefault();
  1958. if (rowElement == null)
  1959. {
  1960. //row element does not exist
  1961. //create a new one
  1962. rowElement = CreateEmptyRow(row);
  1963. //row elements must appear in order inside sheetData element
  1964. if (worksheet.Root
  1965. .Element(ns + "sheetData").HasElements)
  1966. { //if there are more rows already defined at sheetData element
  1967. //find the row with the inmediate higher index for the row containing the cell to set the value to
  1968. XElement rowAfterElement = FindRowAfter(worksheet, row);
  1969. //if there is a row with an inmediate higher index already defined at sheetData
  1970. if (rowAfterElement != null)
  1971. {
  1972. //add the new row before the row with an inmediate higher index
  1973. rowAfterElement.AddBeforeSelf(rowElement);
  1974. }
  1975. else
  1976. { //this row is going to be the one with the highest index (add it as the last element for sheetData)
  1977. worksheet.Root.Element(ns + "sheetData").Elements(ns + "row").Last().AddAfterSelf(rowElement);
  1978. }
  1979. }
  1980. else
  1981. { //there are no other rows already defined at sheetData
  1982. //Add a new row elemento to sheetData
  1983. worksheet
  1984. .Root
  1985. .Element(ns + "sheetData")
  1986. .Add(
  1987. rowElement //= CreateEmptyRow(row)
  1988. );
  1989. }
  1990. //Add the new cell to the row Element
  1991. rowElement.Add(newCellXElement);
  1992. }
  1993. else
  1994. {
  1995. //row containing the cell to set the value to is already defined at sheetData
  1996. //look if cell already exist at that row
  1997. XElement currentCellXElement = rowElement
  1998. .Elements(ns + "c")
  1999. .Where(
  2000. t => t.Attribute("r").Value == cellReference
  2001. ).FirstOrDefault();
  2002. if (currentCellXElement == null)
  2003. { //cell element does not exist at row indicated as parameter
  2004. //find the inmediate right column for the cell to set the value to
  2005. XElement columnAfterXElement = FindColumAfter(worksheet, row, column);
  2006. if (columnAfterXElement != null)
  2007. {
  2008. //Insert the new cell before the inmediate right column
  2009. columnAfterXElement.AddBeforeSelf(newCellXElement);
  2010. }
  2011. else
  2012. { //There is no inmediate right cell
  2013. //Add the new cell as the last element for the row
  2014. rowElement.Add(newCellXElement);
  2015. }
  2016. }
  2017. else
  2018. {
  2019. //cell alreay exist
  2020. //replace the current cell with that with the new value
  2021. currentCellXElement.ReplaceWith(newCellXElement);
  2022. }
  2023. }
  2024. }
  2025. /// <summary>
  2026. /// Adds a given worksheet to the document
  2027. /// </summary>
  2028. /// <param name="worksheet">Worksheet document to add</param>
  2029. /// <returns>Worksheet part just added</returns>
  2030. public static WorksheetPart Add(SpreadsheetDocument doc, XDocument worksheet)
  2031. {
  2032. // Associates base content to a new worksheet part
  2033. WorkbookPart workbook = doc.WorkbookPart;
  2034. WorksheetPart worksheetPart = workbook.AddNewPart<WorksheetPart>();
  2035. worksheetPart.PutXDocument(worksheet);
  2036. // Associates the worksheet part to the workbook part
  2037. XDocument document = doc.WorkbookPart.GetXDocument();
  2038. int sheetId =
  2039. document.Root
  2040. .Element(ns + "sheets")
  2041. .Elements(ns + "sheet")
  2042. .Count() + 1;
  2043. int worksheetCount =
  2044. document.Root
  2045. .Element(ns + "sheets")
  2046. .Elements(ns + "sheet")
  2047. .Where(
  2048. t =>
  2049. t.Attribute("name").Value.StartsWith("sheet", StringComparison.OrdinalIgnoreCase)
  2050. )
  2051. .Count() + 1;
  2052. // Adds content to workbook document to reference worksheet document
  2053. document.Root
  2054. .Element(ns + "sheets")
  2055. .Add(
  2056. new XElement(ns + "sheet",
  2057. new XAttribute("name", string.Format("sheet{0}", worksheetCount)),
  2058. new XAttribute("sheetId", sheetId),
  2059. new XAttribute(relationshipsns + "id", workbook.GetIdOfPart(worksheetPart))
  2060. )
  2061. );
  2062. doc.WorkbookPart.PutXDocument();
  2063. return worksheetPart;
  2064. }
  2065. }
  2066. }