NanoXLSX.Compatibility 3.2.0
Loading...
Searching...
No Matches
ExternalLinkWorkbookInlineWriter.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.Exceptions;
10using NanoXLSX.Interfaces.Writer;
11using NanoXLSX.Registry;
12using NanoXLSX.Registry.Attributes;
13using NanoXLSX.Utils;
14using NanoXLSX.Utils.Xml;
15using System.Collections.Generic;
16
18{
19 [NanoXlsxQueuePlugIn(PlugInUUID = "EXTERNAL_LINK_INLINE_WORKBOOK_WRITER", QueueUUID = PlugInUUID.WorkbookInlineWriter, PlugInOrder = 100000)]
20 internal class ExternalLinkWorkbookInlineWriter : IPluginInlineWriter
21 {
22 #region properties
26 public Workbook Workbook { get; set; }
30 public IWriteContext WriteContext { get; set; } // NoOp
34 public XmlElement RootElement { get; set; }
38 public XmlElement XmlElement { get; } // NoOp
39 #endregion
40 #region methods
47 public void Init(ref XmlElement rootElement, Workbook workbook, int? index = null)
48 {
49 Workbook = workbook;
50 RootElement = rootElement;
51 }
52
56 public void Execute()
57 {
58 XmlElement externalReferences = GetExternalReferences();
59 if (externalReferences == null)
60 {
61 return; // Nothing to do
62 }
63 // XSD requires externalReferences to be after (mandatory) sheets and before (already existing) defined names
64 RootElement.AddChildElementAfter(externalReferences, "functionGroups", "sheets"); // Add <externalReferences> to <workbook>
65 ReplaceDefinedNames();
66 // TODO add further workbook-related processing, if external links are somewhere else too
67 }
68
72 private void ReplaceDefinedNames()
73 {
74 Dictionary<int, ExternalLinkResolution> externalLinks = Workbook.AuxiliaryData.GetData<Dictionary<int, ExternalLinkResolution>>(PlugInUUID.CompatibilityInlineProcessor, CompatibilityConstants.EXTERNAL_LINK_RESOLVED_DEFINED_NAMES_ENTITY);
75 if (!Workbook.Features.ContainsDefinedNames || externalLinks == null || externalLinks.Count == 0)
76 {
77 return; // No defined names or external links to process
78 }
79 IEnumerable<XmlElement> definedNames = RootElement.FindChildElementsByNameAndAttribute("definedName", "name");
80 int index = 0;
81 foreach (XmlElement definedName in definedNames)
82 {
83 if (externalLinks.TryGetValue(index, out ExternalLinkResolution value))
84 {
85 definedName.InnerValue = value.Expression;
86 }
87 index++;
88 }
89 }
95 private XmlElement GetExternalReferences()
96 {
97 List<ExternalLink> externalLinks = Workbook.AuxiliaryData.GetDataList<ExternalLink>(PlugInUUID.CompatibilityInlineProcessor, CompatibilityConstants.EXTERNAL_LINK_OBJECT_ENTITY);
98 if (externalLinks.Count == 0)
99 {
100 return null;
101 }
102
103 XmlElement externalReferences = XmlElement.CreateElement("externalReferences");
104 for (int i = 0; i < externalLinks.Count; i++)
105 {
106 string uniquePackagePartIndex = CompatibilityConstants.UNIQUE_PACKAGE_PART_INDEX_PREFIX + ParserUtils.ToString(i);
107 string relationshipId = Workbook.AuxiliaryData.GetData<string>(PlugInUUID.WriterPackageRegistryQueue, PlugInUUID.PackagePartRelationshipId, uniquePackagePartIndex);
108 if (string.IsNullOrWhiteSpace(relationshipId))
109 {
110 throw new IOException("The workbook relationship ID for external link package part '" + uniquePackagePartIndex + "' is not available.");
111 }
112 externalReferences.AddChildElementWithAttribute("externalReference", "id", relationshipId, "", "r");
113 }
114 return externalReferences;
115 }
116 #endregion
117 }
118}