NanoXLSX.Compatibility 3.2.0
Loading...
Searching...
No Matches
ExternalLinkWorkbookReader.cs
1/*
2 * NanoXLSX is a small .NET library to generate and read XLSX (Microsoft Excel 2007 or newer) files in an easy and native way
3 * Copyright Raphael Stoeckli © 2026
4 * This library is licensed under the MIT License.
5 * You find a copy of the license in project folder or on: http://opensource.org/licenses/MIT
6 */
7
8using NanoXLSX.Interfaces;
9using NanoXLSX.Interfaces.Reader;
10using NanoXLSX.Registry;
11using NanoXLSX.Registry.Attributes;
12using NanoXLSX.Utils;
13using NanoXLSX.Utils.Xml;
14using System;
15using System.Collections.Generic;
16using System.IO;
17using System.Text;
18using System.Xml;
19
21{
25 [NanoXlsxQueuePlugIn(PlugInUUID = "EXTERNAL_LINK_WORKBOOK_READER", QueueUUID = PlugInUUID.WorkbookInlineReader, PlugInOrder = 10000)]
26 internal class ExternalLinkWorkbookReader : IPluginInlineReader
27 {
28 #region privateFields
29 private Stream stream;
30 #endregion
31 #region properties
35 public Action<Stream, Workbook, string, IOptions, int?> InlinePluginHandler { get; set; }
39 public Workbook Workbook { get; set; }
40 #endregion
41 #region methods
42
50 public void Init(Stream stream, Workbook workbook, IOptions readerOptions, int? index = null)
51 {
52 this.stream = stream;
53 this.Workbook = workbook;
54 }
55
59 public void Execute()
60 {
61 try
62 {
63 List<string> rIds = new List<string>();
64 List<ExternalDefinedNameReference> definedNames = new List<ExternalDefinedNameReference>();
65 using (XmlReader reader = XmlReader.Create(stream, XmlStreamUtils.CreateSettings()))
66 {
67 while (reader.Read())
68 {
69 if (XmlStreamUtils.IsElement(reader, "externalReferences"))
70 {
71 ReadExternalReferencesRIds(reader.ReadSubtree(), rIds);
72 }
73 else if (XmlStreamUtils.IsElement(reader, "definedNames"))
74 {
75 ReadExternalDefinedNames(reader.ReadSubtree(), definedNames);
76 }
77 }
78 }
79 if (rIds.Count > 0)
80 {
81 Workbook.AuxiliaryData.SetData(PlugInUUID.CompatibilityInlineProcessor, CompatibilityConstants.EXTERNAL_REFERENCE_WORKBOOK_RID_ENTITY, rIds);
82 }
83 if (definedNames.Count > 0)
84 {
85 Workbook.AuxiliaryData.SetData(PlugInUUID.CompatibilityInlineProcessor, CompatibilityConstants.EXTERNAL_REFERENCE_DEFINED_NAMES_ENTITY, definedNames);
86 }
87
88 }
89 catch (Exception ex)
90 {
91 throw new Exceptions.IOException("The XML entry could not be read from the " + nameof(stream) + ". Please see the inner exception:", ex);
92 }
93 }
94
95 private static void ReadExternalReferencesRIds(XmlReader references, List<string> rIds)
96 {
97 while (references.Read())
98 {
99 if (XmlStreamUtils.IsElement(references, "externalReference"))
100 {
101 string rid = references.GetAttribute("r:id");
102 if (rid != null)
103 {
104 rIds.Add(rid);
105 }
106 }
107 }
108 }
109
110 private static void ReadExternalDefinedNames(XmlReader definitions, List<ExternalDefinedNameReference> definedNames)
111 {
112 while (definitions.Read())
113 {
114 if (!XmlStreamUtils.IsElement(definitions, "definedName"))
115 {
116 continue;
117 }
118
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))
124 {
125 definedNames.Add(new ExternalDefinedNameReference(name, localSheetIndex, expression));
126 }
127 }
128 }
129
130 private static string ReadElementText(XmlReader reader)
131 {
132 if (reader.IsEmptyElement)
133 {
134 return string.Empty;
135 }
136 StringBuilder builder = new StringBuilder();
137 while (reader.Read())
138 {
139 if (reader.NodeType == XmlNodeType.EndElement)
140 {
141 break;
142 }
143 if (reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.CDATA ||
144 reader.NodeType == XmlNodeType.SignificantWhitespace)
145 {
146 builder.Append(reader.Value);
147 }
148 }
149 return builder.ToString();
150 }
151 }
152
156 internal sealed class ExternalDefinedNameReference
157 {
158 public string Name { get; }
159 public int? LocalSheetIndex { get; }
160 public string Expression { get; }
161
162 public ExternalDefinedNameReference(string name, int? localSheetIndex, string expression)
163 {
164 Name = name;
165 LocalSheetIndex = localSheetIndex;
166 Expression = expression;
167 }
168 }
169 #endregion
170}