8using NanoXLSX.Exceptions;
10using NanoXLSX.Registry;
11using NanoXLSX.Registry.Attributes;
14using NanoXLSX.Utils.Xml;
15using System.Collections.Generic;
20using static
NanoXLSX.Styles.NumberFormat;
27 [NanoXlsxPlugIn(PlugInUUID = PlugInUUID.StyleWriter)]
28 internal class StyleWriter : IPlugInWriter
31 private StyleManager styles;
32 private XmlElement styleSheet;
38 public Workbook Workbook {
get;
set; }
43 public XmlElement XmlElement {
get => styleSheet; }
50 internal StyleWriter()
60 public void Init(IBaseWriter baseWriter)
62 this.styles = baseWriter.Styles;
63 this.Workbook = baseWriter.Workbook;
71 styleSheet = XmlElement.CreateElement(
"styleSheet");
72 styleSheet.AddDefaultXmlNameSpace(
"http://schemas.openxmlformats.org/spreadsheetml/2006/main");
73 styleSheet.AddNameSpaceAttribute(
"mc",
"xmlns",
"http://schemas.openxmlformats.org/markup-compatibility/2006");
74 styleSheet.AddNameSpaceAttribute(
"x14ac",
"xmlns",
"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
75 styleSheet.AddAttribute(
"mc:Ignorable",
"x14ac");
76 int numFormatCount = styles.GetNumberFormatStyleNumber();
77 int fontCount = styles.GetFontStyleNumber();
78 int fillCount = styles.GetFillStyleNumber();
79 int borderCount = styles.GetBorderStyleNumber();
80 int styleCount = styles.GetStyleNumber();
81 if (numFormatCount > 0)
83 XmlElement numFmts = XmlElement.CreateElementWithAttribute(
"numFmts",
"count", ParserUtils.ToString(numFormatCount));
84 numFmts.AddChildElements(GetNumberFormatElements());
85 styleSheet.AddChildElement(numFmts);
87 XmlElement fonts = XmlElement.CreateElementWithAttribute(
"fonts",
"count", ParserUtils.ToString(fontCount));
88 fonts.AddAttribute(
"knownFonts",
"1",
"x14ac");
89 fonts.AddChildElements(GetFontElements());
90 styleSheet.AddChildElement(fonts);
91 XmlElement fills = XmlElement.CreateElementWithAttribute(
"fills",
"count", ParserUtils.ToString(fillCount));
92 fills.AddChildElements(GetFillElements());
93 styleSheet.AddChildElement(fills);
94 XmlElement borders = XmlElement.CreateElementWithAttribute(
"borders",
"count", ParserUtils.ToString(borderCount));
95 borders.AddChildElements(GetBorderElements());
96 styleSheet.AddChildElement(borders);
97 XmlElement cellXfs = XmlElement.CreateElementWithAttribute(
"cellXfs",
"count", ParserUtils.ToString(styleCount));
98 cellXfs.AddChildElements(GetCellXfElements());
99 styleSheet.AddChildElement(cellXfs);
100 if (Workbook.WorkbookMetadata !=
null)
102 XmlElement mruElement = GetMruElement();
103 if (mruElement !=
null)
105 XmlElement colors = styleSheet.AddChildElement(
"colors");
106 colors.AddChildElement(mruElement);
110 WriterPlugInHandler.HandleInlineQueuePlugins(ref styleSheet, Workbook, PlugInUUID.StyleInlineWriter);
117 private List<XmlElement> GetBorderElements()
119 Border[] borderStyles = styles.GetBorders();
120 List<XmlElement> borders =
new List<XmlElement>(borderStyles.Length);
121 foreach (Border item
in borderStyles)
123 XmlElement border = XmlElement.CreateElement(
"border");
124 if (item.DiagonalDown && !item.DiagonalUp) { border.AddAttribute(
"diagonalDown",
"1"); }
125 else if (!item.DiagonalDown && item.DiagonalUp) { border.AddAttribute(
"diagonalUp",
"1"); }
126 else if (item.DiagonalDown && item.DiagonalUp)
128 border.AddAttribute(
"diagonalDown",
"1");
129 border.AddAttribute(
"diagonalUp",
"1");
131 if (item.LeftStyle != StyleValue.None)
133 XmlElement left = border.AddChildElementWithAttribute(
"left",
"style", Border.GetStyleName(item.LeftStyle));
134 if (!
string.IsNullOrEmpty(item.LeftColor)) { left.AddChildElementWithAttribute(
"color",
"rgb", item.LeftColor); }
135 else { left.AddChildElementWithAttribute(
"color",
"auto",
"1"); }
139 border.AddChildElement(
"left");
141 if (item.RightStyle != StyleValue.None)
143 XmlElement right = border.AddChildElementWithAttribute(
"right",
"style", Border.GetStyleName(item.RightStyle));
144 if (!
string.IsNullOrEmpty(item.RightColor)) { right.AddChildElementWithAttribute(
"color",
"rgb", item.RightColor); }
145 else { right.AddChildElementWithAttribute(
"color",
"auto",
"1"); }
149 border.AddChildElement(
"right");
151 if (item.TopStyle != StyleValue.None)
153 XmlElement top = border.AddChildElementWithAttribute(
"top",
"style", Border.GetStyleName(item.TopStyle));
154 if (!
string.IsNullOrEmpty(item.TopColor)) { top.AddChildElementWithAttribute(
"color",
"rgb", item.TopColor); }
155 else { top.AddChildElementWithAttribute(
"color",
"auto",
"1"); }
159 border.AddChildElement(
"top");
161 if (item.BottomStyle != StyleValue.None)
163 XmlElement bottom = border.AddChildElementWithAttribute(
"bottom",
"style", Border.GetStyleName(item.BottomStyle));
164 if (!
string.IsNullOrEmpty(item.BottomColor)) { bottom.AddChildElementWithAttribute(
"color",
"rgb", item.BottomColor); }
165 else { bottom.AddChildElementWithAttribute(
"color",
"auto",
"1"); }
169 border.AddChildElement(
"bottom");
171 if (item.DiagonalStyle != StyleValue.None)
173 XmlElement diagonal = border.AddChildElementWithAttribute(
"diagonal",
"style", Border.GetStyleName(item.DiagonalStyle));
174 if (!
string.IsNullOrEmpty(item.DiagonalColor)) { diagonal.AddChildElementWithAttribute(
"color",
"rgb", item.DiagonalColor); }
175 else { diagonal.AddChildElementWithAttribute(
"color",
"auto",
"1"); }
179 border.AddChildElement(
"diagonal");
190 private List<XmlElement> GetFontElements()
192 Font[] fontStyles = styles.GetFonts();
193 List<XmlElement> fonts =
new List<XmlElement>(fontStyles.Length);
194 foreach (Font item
in fontStyles)
196 XmlElement font = XmlElement.CreateElement(
"font");
197 if (item.Bold) { font.AddChildElement(
"b"); }
198 if (item.Italic) { font.AddChildElement(
"i"); }
199 if (item.Strike) { font.AddChildElement(
"strike"); }
200 if (item.Underline != UnderlineValue.None && item.Underline != UnderlineValue.Single)
202 font.AddChildElementWithAttribute(
"u",
"val", Font.GetUnderlineName(item.Underline));
204 else if (item.Underline == UnderlineValue.Single)
206 font.AddChildElement(
"u");
208 if (item.VerticalAlign != VerticalTextAlignValue.None)
210 font.AddChildElementWithAttribute(
"vertAlign",
"val", Font.GetVerticalTextAlignName(item.VerticalAlign));
212 font.AddChildElementWithAttribute(
"sz",
"val", ParserUtils.ToString(item.Size));
213 if (
string.IsNullOrEmpty(item.ColorValue))
215 font.AddChildElementWithAttribute(
"color",
"theme", ParserUtils.ToString((
int)item.ColorTheme));
219 font.AddChildElementWithAttribute(
"color",
"rgb", item.ColorValue);
221 font.AddChildElementWithAttribute(
"name",
"val", item.Name);
222 font.AddChildElementWithAttribute(
"family",
"val", ParserUtils.ToString((
int)item.Family));
223 if (item.Scheme != SchemeValue.None)
225 if (item.Scheme == SchemeValue.Major)
226 { font.AddChildElementWithAttribute(
"scheme",
"val",
"major"); }
227 else if (item.Scheme == SchemeValue.Minor)
228 { font.AddChildElementWithAttribute(
"scheme",
"val",
"minor"); }
230 font.AddChildElementWithAttribute(
"charset",
"val", ParserUtils.ToString((
int)item.Charset));
240 private List<XmlElement> GetFillElements()
242 Fill[] fillStyles = styles.GetFills();
243 List<XmlElement> fills =
new List<XmlElement>(fillStyles.Length);
244 foreach (Fill item
in fillStyles)
246 XmlElement fill = XmlElement.CreateElement(
"fill");
247 XmlElement patternFill = fill.AddChildElement(
"patternFill");
248 patternFill.AddAttribute(
"patternType", Fill.GetPatternName(item.PatternFill));
249 if (item.PatternFill == PatternValue.Solid)
251 patternFill.AddChildElementWithAttribute(
"fgColor",
"rgb", item.ForegroundColor);
252 patternFill.AddChildElementWithAttribute(
"bgColor",
"indexed", ParserUtils.ToString(item.IndexedColor));
254 else if (item.PatternFill == PatternValue.MediumGray || item.PatternFill == PatternValue.LightGray || item.PatternFill == PatternValue.Gray0625 || item.PatternFill == PatternValue.DarkGray)
256 patternFill.AddChildElementWithAttribute(
"fgColor",
"rgb", item.ForegroundColor);
257 if (!
string.IsNullOrEmpty(item.BackgroundColor))
259 patternFill.AddChildElementWithAttribute(
"bgColor",
"rgb", item.BackgroundColor);
271 private List<XmlElement> GetNumberFormatElements()
273 NumberFormat[] numberFormatStyles = styles.GetNumberFormats();
274 List<XmlElement> elements =
new List<XmlElement>(numberFormatStyles.Length);
275 foreach (NumberFormat item
in numberFormatStyles)
277 if (item.IsCustomFormat)
279 if (
string.IsNullOrEmpty(item.CustomFormatCode))
281 throw new FormatException(
"The number format style component with the ID " + ParserUtils.ToString(item.CustomFormatID) +
" cannot be null or empty");
285 XmlElement element = XmlElement.CreateElementWithAttribute(
"numFmt",
"formatCode", XmlUtils.SanitizeXmlValue(item.CustomFormatCode));
286 element.AddAttribute(
"numFmtId", ParserUtils.ToString(item.CustomFormatID));
287 elements.Add(element);
297 private List<XmlElement> GetCellXfElements()
299 Style[] styleItems = this.styles.GetStyles();
300 List<XmlElement> xfs =
new List<XmlElement>(styleItems.Length);
301 foreach (Style style
in styleItems)
303 int textRotation = style.CurrentCellXf.CalculateInternalRotation();
304 XmlElement alignment =
null;
305 XmlElement protection =
null;
306 if (style.CurrentCellXf.HorizontalAlign != HorizontalAlignValue.None || style.CurrentCellXf.VerticalAlign != VerticalAlignValue.None || style.CurrentCellXf.Alignment != TextBreakValue.None || textRotation != 0)
308 alignment = XmlElement.CreateElement(
"alignment");
309 if (style.CurrentCellXf.HorizontalAlign != HorizontalAlignValue.None)
311 string alignValue = CellXf.GetHorizontalAlignName(style.CurrentCellXf.HorizontalAlign);
312 alignment.AddAttribute(
"horizontal", alignValue);
314 if (style.CurrentCellXf.VerticalAlign != VerticalAlignValue.None)
316 string alignValue = CellXf.GetVerticalAlignName(style.CurrentCellXf.VerticalAlign);
317 alignment.AddAttribute(
"vertical", alignValue);
319 if (style.CurrentCellXf.Indent > 0 &&
320 (style.CurrentCellXf.HorizontalAlign == HorizontalAlignValue.Left
321 || style.CurrentCellXf.HorizontalAlign == HorizontalAlignValue.Right
322 || style.CurrentCellXf.HorizontalAlign == HorizontalAlignValue.Distributed))
324 alignment.AddAttribute(
"indent", ParserUtils.ToString(style.CurrentCellXf.Indent));
326 if (style.CurrentCellXf.Alignment != TextBreakValue.None)
328 if (style.CurrentCellXf.Alignment == TextBreakValue.ShrinkToFit) { alignment.AddAttribute(
"shrinkToFit",
"1"); }
329 else { alignment.AddAttribute(
"wrapText",
"1"); }
331 if (textRotation != 0)
333 alignment.AddAttribute(
"textRotation", ParserUtils.ToString(textRotation));
336 if (!style.CurrentCellXf.Locked || style.CurrentCellXf.Hidden)
338 protection = XmlElement.CreateElement(
"protection");
339 if (style.CurrentCellXf.Hidden && style.CurrentCellXf.Locked)
341 protection.AddAttribute(
"hidden",
"1");
343 else if (style.CurrentCellXf.Hidden && !style.CurrentCellXf.Locked)
345 protection.AddAttribute(
"hidden",
"1");
346 protection.AddAttribute(
"locked",
"0");
348 else if (!style.CurrentCellXf.Hidden && !style.CurrentCellXf.Locked)
350 protection.AddAttribute(
"locked",
"0");
358 XmlElement xf = XmlElement.CreateElement(
"xf");
359 if (style.CurrentNumberFormat.IsCustomFormat)
361 xf.AddAttribute(
"numFmtId", ParserUtils.ToString(style.CurrentNumberFormat.CustomFormatID));
365 int formatNumber = (int)style.CurrentNumberFormat.Number;
366 xf.AddAttribute(
"numFmtId", ParserUtils.ToString(formatNumber));
368 xf.AddAttribute(
"borderId", ParserUtils.ToString(style.CurrentBorder.InternalID.Value));
369 xf.AddAttribute(
"fillId", ParserUtils.ToString(style.CurrentFill.InternalID.Value));
370 xf.AddAttribute(
"fontId", ParserUtils.ToString(style.CurrentFont.InternalID.Value));
371 if (!style.CurrentFont.IsDefaultFont)
373 xf.AddAttribute(
"applyFont",
"1");
375 if (style.CurrentFill.PatternFill != PatternValue.None)
377 xf.AddAttribute(
"applyFill",
"1");
379 if (!style.CurrentBorder.IsEmpty())
381 xf.AddAttribute(
"applyBorder",
"1");
383 if (alignment !=
null || style.CurrentCellXf.ForceApplyAlignment)
385 xf.AddAttribute(
"applyAlignment",
"1");
387 if (protection !=
null)
389 xf.AddAttribute(
"applyProtection",
"1");
391 if (style.CurrentNumberFormat.Number != FormatNumber.None)
393 xf.AddAttribute(
"applyNumberFormat",
"1");
395 if (alignment !=
null || protection !=
null)
397 xf.AddChildElement(alignment);
398 xf.AddChildElement(protection);
409 private XmlElement GetMruElement()
411 XmlElement mruColors =
null;
412 List<string> tempColors =
new List<string>();
413 foreach (
string item
in ((Workbook)this.Workbook).GetMruColors())
415 if (item == Fill.DefaultColor)
419 if (!tempColors.Contains(item)) { tempColors.Add(item); }
421 if (tempColors.Count > 0)
423 mruColors = XmlElement.CreateElement(
"mruColors");
424 foreach (
string item
in tempColors)
426 mruColors.AddChildElementWithAttribute(
"color",
"rgb", item);