8using NanoXLSX.Interfaces;
9using NanoXLSX.Interfaces.Reader;
10using NanoXLSX.Registry;
11using NanoXLSX.Registry.Attributes;
13using NanoXLSX.Utils.Xml;
15using System.Collections.Generic;
25 [NanoXlsxQueuePlugIn(PlugInUUID =
"EXTERNAL_LINK_WORKBOOK_READER", QueueUUID = PlugInUUID.WorkbookInlineReader, PlugInOrder = 10000)]
26 internal class ExternalLinkWorkbookReader : IPluginInlineReader
29 private Stream stream;
35 public Action<Stream, Workbook, string, IOptions, int?> InlinePluginHandler {
get;
set; }
39 public Workbook Workbook {
get;
set; }
50 public void Init(Stream stream, Workbook workbook, IOptions readerOptions,
int? index =
null)
53 this.Workbook = workbook;
63 List<string> rIds =
new List<string>();
64 List<ExternalDefinedNameReference> definedNames =
new List<ExternalDefinedNameReference>();
65 using (XmlReader reader = XmlReader.Create(stream, XmlStreamUtils.CreateSettings()))
69 if (XmlStreamUtils.IsElement(reader,
"externalReferences"))
71 ReadExternalReferencesRIds(reader.ReadSubtree(), rIds);
73 else if (XmlStreamUtils.IsElement(reader,
"definedNames"))
75 ReadExternalDefinedNames(reader.ReadSubtree(), definedNames);
81 Workbook.AuxiliaryData.SetData(PlugInUUID.CompatibilityInlineProcessor, CompatibilityConstants.EXTERNAL_REFERENCE_WORKBOOK_RID_ENTITY, rIds);
83 if (definedNames.Count > 0)
85 Workbook.AuxiliaryData.SetData(PlugInUUID.CompatibilityInlineProcessor, CompatibilityConstants.EXTERNAL_REFERENCE_DEFINED_NAMES_ENTITY, definedNames);
91 throw new Exceptions.IOException(
"The XML entry could not be read from the " + nameof(stream) +
". Please see the inner exception:", ex);
95 private static void ReadExternalReferencesRIds(XmlReader references, List<string> rIds)
97 while (references.Read())
99 if (XmlStreamUtils.IsElement(references,
"externalReference"))
101 string rid = references.GetAttribute(
"r:id");
110 private static void ReadExternalDefinedNames(XmlReader definitions, List<ExternalDefinedNameReference> definedNames)
112 while (definitions.Read())
114 if (!XmlStreamUtils.IsElement(definitions,
"definedName"))
119 string name = definitions.GetAttribute(
"name");
120 string localSheetId = definitions.GetAttribute(
"localSheetId");
121 int? localSheetIndex =
string.IsNullOrEmpty(localSheetId) ? (
int?)
null : ParserUtils.ParseInt(localSheetId);
122 string expression = ReadElementText(definitions);
123 if (ExternalLinkFormulaUtils.DetectExternalLinkId(expression))
125 definedNames.Add(
new ExternalDefinedNameReference(name, localSheetIndex, expression));
130 private static string ReadElementText(XmlReader reader)
132 if (reader.IsEmptyElement)
136 StringBuilder builder =
new StringBuilder();
137 while (reader.Read())
139 if (reader.NodeType == XmlNodeType.EndElement)
143 if (reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.CDATA ||
144 reader.NodeType == XmlNodeType.SignificantWhitespace)
146 builder.Append(reader.Value);
149 return builder.ToString();
156 internal sealed class ExternalDefinedNameReference
158 public string Name {
get; }
159 public int? LocalSheetIndex {
get; }
160 public string Expression {
get; }
162 public ExternalDefinedNameReference(
string name,
int? localSheetIndex,
string expression)
165 LocalSheetIndex = localSheetIndex;
166 Expression = expression;