8using NanoXLSX.Interfaces.Writer;
9using NanoXLSX.Registry;
10using NanoXLSX.Registry.Attributes;
12using NanoXLSX.Utils.Xml;
13using System.Collections.Generic;
14using System.Collections.ObjectModel;
19 [NanoXlsxQueuePlugIn(PlugInUUID =
"EXTERNAL_LINK_WRITER", QueueUUID = PlugInUUID.WriterAppendingQueue, PlugInOrder = 20001)]
20 internal class ExternalLinkWriter : IPluginIndexedWriter
23 private string currentUniqueIndex;
24 private List<ExternalLink> externalLinks;
26 XmlElement xmlElement;
33 public int CurrentIndex {
get;
set; }
37 public string CurrentUniquePackagePartIndex => currentUniqueIndex;
41 public int MaxIndex => maxIndex;
46 public Workbook Workbook {
get;
set; }
50 public XmlElement XmlElement => xmlElement;
57 public void Init(IBaseWriter baseWriter)
59 this.Workbook = baseWriter.Workbook;
60 externalLinks = Workbook.AuxiliaryData
61 .GetDataList<ExternalLink>(PlugInUUID.CompatibilityInlineProcessor, CompatibilityConstants.EXTERNAL_LINK_OBJECT_ENTITY)
62 .OfType<ExternalLink>()
64 maxIndex = externalLinks.Count - 1;
72 currentUniqueIndex = CompatibilityConstants.UNIQUE_PACKAGE_PART_INDEX_PREFIX + ParserUtils.ToString(CurrentIndex);
73 xmlElement = GetElement(externalLinks[CurrentIndex]);
81 internal static XmlElement GetElement(ExternalLink externalLink)
83 IReadOnlyList<ExternalLinkUriRelationship> relationships = externalLink.GetUriRelationships();
84 XmlElement element = XmlElement.CreateElement(
"externalLink");
85 element.AddDefaultXmlNameSpace(
"http://schemas.openxmlformats.org/spreadsheetml/2006/main");
86 element.AddNameSpaceAttribute(
"mc",
"xmlns",
"http://schemas.openxmlformats.org/markup-compatibility/2006");
87 element.AddNameSpaceAttribute(
"x14",
"xmlns",
"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main");
88 element.AddNameSpaceAttribute(
"xxl21",
"xmlns",
"http://schemas.microsoft.com/office/spreadsheetml/2021/extlinks2021");
89 element.AddAttribute(
"mc:Ignorable",
"x14 xxl21");
91 XmlElement externalBook = XmlElement.CreateElement(
"externalBook");
92 externalBook.AddNameSpaceAttribute(
"r",
"xmlns",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships");
93 externalBook.AddAttribute(
"r:id", relationships[0].Id);
94 element.AddChildElement(externalBook);
96 if (relationships.Count > 1)
98 XmlElement alternateUrls = XmlElement.CreateElement(
"alternateUrls",
"xxl21");
99 foreach (ExternalLinkUriRelationship relationship
in relationships)
101 if (relationship.Role == ExternalLinkUriRole.AbsoluteAlternate)
103 XmlElement absoluteUrl = XmlElement.CreateElement(
"absoluteUrl",
"xxl21");
104 absoluteUrl.AddAttribute(
"r:id", relationship.Id);
105 alternateUrls.AddChildElement(absoluteUrl);
107 else if (relationship.Role == ExternalLinkUriRole.RelativeAlternate)
109 XmlElement relativeUrl = XmlElement.CreateElement(
"relativeUrl",
"xxl21");
110 relativeUrl.AddAttribute(
"r:id", relationship.Id);
111 alternateUrls.AddChildElement(relativeUrl);
114 externalBook.AddChildElement(alternateUrls);
117 if (externalLink.Worksheets.Count > 0)
119 XmlElement sheetNames = XmlElement.CreateElement(
"sheetNames");
120 XmlElement sheetDataSet = XmlElement.CreateElement(
"sheetDataSet");
123 foreach (ExternalWorksheet sheet
in externalLink.Worksheets)
126 XmlElement sheetName = XmlElement.CreateElement(
"sheetName");
127 sheetName.AddAttribute(
"val", XmlUtils.SanitizeXmlValue(sheet.Name));
128 sheetNames.AddChildElement(sheetName);
130 XmlElement sheetData = XmlElement.CreateElement(
"sheetData");
131 sheetData.AddAttribute(
"sheetId", ParserUtils.ToString(sheetId));
132 if (sheet.RefreshErros !=
null)
135 sheetData.AddAttribute(
"refreshErrors", ParserUtils.ToString(sheet.RefreshErros.Value ==
true ? 1 : 0));
137 List<XmlElement> row = GetRowData(sheet);
138 foreach (XmlElement rowElement
in row)
140 sheetData.AddChildElement(rowElement);
142 sheetDataSet.AddChildElement(sheetData);
145 externalBook.AddChildElement(sheetNames);
146 externalBook.AddChildElement(sheetDataSet);
148 if (externalLink.DefinedNames.Count > 0)
150 XmlElement definedNames = XmlElement.CreateElement(
"definedNames");
151 foreach (ExternalDefinedName externalDefinedName
in externalLink.DefinedNames)
153 XmlElement definedName = XmlElement.CreateElement(
"definedName");
154 definedName.AddAttribute(
"name", XmlUtils.SanitizeXmlValue(externalDefinedName.Name));
155 if (externalDefinedName.RefersTo !=
null)
157 definedName.AddAttribute(
"refersTo", XmlUtils.SanitizeXmlValue(externalDefinedName.RefersTo));
159 if (externalDefinedName.RelationshipId !=
null)
161 definedName.AddAttribute(
"sheetId", XmlUtils.SanitizeXmlValue(externalDefinedName.RelationshipId));
163 definedNames.AddChildElement(definedName);
165 if (externalBook.FindChildElementsByName(
"sheetDataSet").Any())
167 externalBook.AddChildElementBefore(definedNames,
"sheetDataSet");
171 externalBook.AddChildElement(definedNames);
182 private static List<XmlElement> GetRowData(ExternalWorksheet sheet)
184 if (sheet.Cells.Count == 0)
186 return new List<XmlElement>();
188 ReadOnlyDictionary<Address, ExternalCellValue> cells = sheet.Cells;
189 SortedDictionary<int, XmlElement> rows =
new SortedDictionary<int, XmlElement>();
191 foreach (KeyValuePair<Address, ExternalCellValue> cell
in cells)
193 if (!rows.TryGetValue(cell.Key.Row, out XmlElement value))
195 XmlElement row = XmlElement.CreateElement(
"row");
196 row.AddAttribute(
"r", ParserUtils.ToString(cell.Key.Row + 1));
198 rows.Add(cell.Key.Row, value);
200 XmlElement element = XmlElement.CreateElement(
"cell");
201 element.AddAttribute(
"r", cell.Key.ToString());
202 string type = GetCellType(cell.Value.Type);
205 element.AddAttribute(
"t", type);
207 if (cell.Value.CellMetadata !=
null)
209 element.AddAttribute(
"vm", ParserUtils.ToString(cell.Value.CellMetadata.Value));
211 if (cell.Value.Type != ExternalCellValue.DataType.Empty)
213 XmlElement valueElement = XmlElement.CreateElement(
"v");
214 valueElement.InnerValue =
215 XmlUtils.SanitizeXmlValue(cell.Value.Value);
216 element.AddChildElement(valueElement);
218 value.AddChildElement(element);
220 return rows.Values.ToList();
228 private static string GetCellType(ExternalCellValue.DataType dataType)
232 case ExternalCellValue.DataType.Boolean:
234 case ExternalCellValue.DataType.Date:
236 case ExternalCellValue.DataType.Error:
238 case ExternalCellValue.DataType.String: