NanoXLSX.Core 3.0.0-rc.3
Loading...
Searching...
No Matches
XmlElement.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 © 2025
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 System.Collections.Generic;
9using System.Linq;
10using System.Xml;
11
12namespace NanoXLSX.Utils.Xml
13{
17 public class XmlElement
18 {
19 private readonly bool hasPrefix;
20 private bool hasNameSpaces;
21 private bool hasDefaultNameSpace;
22 private bool hasAttributes;
23 private bool hasInnerValue;
24 private bool hasChildren;
25 private string innerValue;
26 private string defaultXmlNsUri;
27
31 public string Prefix { get; set; }
35 public string Name { get; private set; }
39 public List<XmlElement> Children { get; private set; }
43 public HashSet<XmlAttribute> Attributes { get; private set; }
47 public Dictionary<string, string> PrefixNameSpaceMap { get; private set; }
48
52 public string InnerValue
53 {
54 get => innerValue;
55 set
56 {
57 if (string.IsNullOrEmpty(value))
58 {
59 innerValue = null;
60 hasInnerValue = false;
61 }
62 else
63 {
64 innerValue = value;
65 hasInnerValue = true;
66 }
67 }
68 }
69
75 internal XmlElement(string name, string prefix)
76 {
77 this.Name = name;
78 this.Prefix = prefix;
79 this.hasPrefix = !string.IsNullOrEmpty(prefix);
80 }
81
89 internal void AddNameSpaceAttribute(string prefix, string rootNameSpace, string uri)
90 {
91 if (string.IsNullOrEmpty(prefix) || string.IsNullOrEmpty(uri))
92 {
93 return;
94 }
95 if (PrefixNameSpaceMap == null)
96 {
97 PrefixNameSpaceMap = new Dictionary<string, string>();
98 }
99 if (!PrefixNameSpaceMap.ContainsKey(prefix))
100 {
101 PrefixNameSpaceMap.Add(prefix, uri);
102 }
103 hasNameSpaces = true;
104 AddAttribute(prefix, uri, rootNameSpace);
105 }
106
111 internal void AddDefaultXmlNameSpace(string defaultXmlNsUri)
112 {
113 this.defaultXmlNsUri = defaultXmlNsUri;
114 hasDefaultNameSpace = true;
115 }
116
123 internal void AddAttribute(string name, string value, string prefix = "")
124 {
125 if (!hasAttributes)
126 {
127 Attributes = new HashSet<XmlAttribute>();
128 hasAttributes = true;
129 }
130 Attributes.Add(XmlAttribute.CreateAttribute(name, value, prefix));
131 }
132
137 internal void AddAttribute(XmlAttribute? nullableAttribute)
138 {
139 if (!nullableAttribute.HasValue)
140 {
141 return;
142 }
143 if (!hasAttributes)
144 {
145 Attributes = new HashSet<XmlAttribute>();
146 hasAttributes = true;
147 }
148 Attributes.Add(nullableAttribute.Value);
149 }
150
155 internal void AddAttributes(IEnumerable<XmlAttribute> attributes)
156 {
157 if (attributes == null || !attributes.Any())
158 {
159 return;
160 }
161 if (!hasAttributes)
162 {
163 Attributes = new HashSet<XmlAttribute>();
164 hasAttributes = true;
165 }
166 foreach (XmlAttribute attribute in attributes)
167 {
168 Attributes.Add(attribute);
169 }
170 }
171
181 internal XmlElement AddChildElementWithAttribute(string name, string attributeName, string attributeValue, string namePrefix = "", string attributePrefix = "")
182 {
183 XmlElement childElement = CreateElementWithAttribute(name, attributeName, attributeValue, namePrefix, attributePrefix);
184 AddChildElement(childElement);
185 return childElement;
186 }
187
195 internal XmlElement AddChildElementWithValue(string name, string innerValue, string prefix = "")
196 {
197 if (string.IsNullOrEmpty(innerValue))
198 {
199 return null; // Omit empty nodes
200 }
201 XmlElement childElement = CreateElement(name, prefix);
202 childElement.InnerValue = innerValue;
203 AddChildElement(childElement);
204 return childElement;
205 }
206
213 internal XmlElement AddChildElement(string name, string prefix = "")
214 {
215 XmlElement childElement = CreateElement(name, prefix);
216 AddChildElement(childElement);
217 return childElement;
218 }
219
224 internal void AddChildElement(XmlElement xmlElement)
225 {
226 if (xmlElement == null)
227 {
228 return;
229 }
230 if (!hasChildren)
231 {
232 Children = new List<XmlElement>();
233 hasChildren = true;
234 }
235 Children.Add(xmlElement);
236 }
237
242 internal void AddChildElements(IEnumerable<XmlElement> xmlElements)
243 {
244 if (xmlElements == null || !xmlElements.Any())
245 {
246 return;
247 }
248 if (!hasChildren)
249 {
250 Children = new List<XmlElement>();
251 hasChildren = true;
252 }
253 Children.AddRange(xmlElements);
254 }
255
260 public XmlDocument TransformToDocument()
261 {
262 XmlDocument doc = new XmlDocument
263 {
264 XmlResolver = null
265 };
266 XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
267 if (hasNameSpaces)
268 {
269 foreach (KeyValuePair<string, string> nameSpace in PrefixNameSpaceMap)
270 {
271 if (nameSpace.Key == "xmlns")
272 {
273 continue;
274 }
275 nsManager.AddNamespace(nameSpace.Key, nameSpace.Value);
276 }
277 }
278 // Create the root element from this instance recursively.
279 System.Xml.XmlElement rootElement = null;
280 if (hasDefaultNameSpace)
281 {
282 rootElement = XmlElement.CreateXmlElement(doc, this, nsManager, defaultXmlNsUri);
283 }
284 else
285 {
286 rootElement = XmlElement.CreateXmlElement(doc, this, nsManager);
287 }
288 doc.AppendChild(rootElement);
289 return doc;
290 }
291
297 public IEnumerable<XmlElement> FindChildElementsByName(string name)
298 {
299 if (!hasChildren)
300 {
301 return Enumerable.Empty<XmlElement>();
302 }
303 List<XmlElement> result = new List<XmlElement>();
304 foreach (XmlElement child in Children)
305 {
306 if (child.Name == name)
307 {
308 result.Add(child);
309 }
310 result.AddRange(child.FindChildElementsByName(name));
311 }
312 return result;
313 }
314
321 public IEnumerable<XmlElement> FindChildElementsByNameAndAttribute(string elementName, string attributeName)
322 {
323 return FindChildElementsByNameAndAttribute(elementName, attributeName, null, false);
324 }
325
333 public IEnumerable<XmlElement> FindChildElementsByNameAndAttribute(string elementName, string attributeName, string attributeValue)
334 {
335 return FindChildElementsByNameAndAttribute(elementName, attributeName, attributeValue, true);
336 }
337
346 private IEnumerable<XmlElement> FindChildElementsByNameAndAttribute(string elementName, string attributeName, string attributeValue, bool useValue)
347 {
348 if (!hasChildren)
349 {
350 return Enumerable.Empty<XmlElement>();
351 }
352 List<XmlElement> result = new List<XmlElement>();
353 foreach (XmlElement child in Children)
354 {
355 if (child.Name == elementName && child.hasAttributes)
356 {
357 XmlAttribute? attribute = XmlAttribute.FindAttribute(attributeName, child.Attributes);
358 if (attribute != null)
359 {
360 if (!useValue || (useValue && attribute.Value.Value == attributeValue))
361 {
362 result.Add(child);
363 }
364 }
365 }
366 result.AddRange(child.FindChildElementsByNameAndAttribute(elementName, attributeName, attributeValue, useValue));
367 }
368 return result;
369 }
370
377 internal static XmlElement CreateElement(string name, string prefix = "")
378 {
379 return new XmlElement(name, prefix);
380 }
381
391 internal static XmlElement CreateElementWithAttribute(string name, string attributeName, string attributeValue, string namePrefix = "", string attributePrefix = "")
392 {
393 XmlElement element = new XmlElement(name, namePrefix)
394 {
395 Attributes = new HashSet<XmlAttribute>()
396 };
397 element.Attributes.Add(XmlAttribute.CreateAttribute(attributeName, attributeValue, attributePrefix));
398 element.hasAttributes = true;
399 return element;
400 }
401
410 private static System.Xml.XmlElement CreateXmlElement(XmlDocument doc, XmlElement customElement, XmlNamespaceManager nsManager, string defaultXmlNsUri = null)
411 {
412 System.Xml.XmlElement xmlElem;
413 if (customElement.hasPrefix)
414 {
415 xmlElem = doc.CreateElement(customElement.Prefix, customElement.Name, nsManager.LookupNamespace(customElement.Prefix));
416 }
417 else
418 {
419 xmlElem = doc.CreateElement(customElement.Name, defaultXmlNsUri);
420 }
421
422 // Add attributes
423 if (customElement.hasAttributes)
424 {
425 foreach (var attr in customElement.Attributes)
426 {
427 if (attr.HasPrefix)
428 {
429 System.Xml.XmlAttribute xmlAttr = doc.CreateAttribute(attr.Prefix, attr.Name, nsManager.LookupNamespace(attr.Prefix));
430 xmlAttr.Value = attr.Value;
431 xmlElem.Attributes.Append(xmlAttr);
432 }
433 else
434 {
435 xmlElem.SetAttribute(attr.Name, attr.Value);
436 }
437 }
438 }
439
440 // Set inner text if available
441 if (customElement.hasInnerValue)
442 {
443 xmlElem.InnerText = customElement.InnerValue;
444 }
445
446 // Process children recursively.
447 if (customElement.hasChildren)
448 {
449 foreach (var child in customElement.Children)
450 {
451 System.Xml.XmlElement childXmlElem = XmlElement.CreateXmlElement(doc, child, nsManager, defaultXmlNsUri);
452 xmlElem.AppendChild(childXmlElem);
453 }
454 }
455 return xmlElem;
456 }
457 }
458}
Class representing an internally used XML element / node.
Definition XmlElement.cs:18
string Name
Name of the element (without prefix).
Definition XmlElement.cs:35
HashSet< XmlAttribute > Attributes
List of attributes of this element. If none, the list is null.
Definition XmlElement.cs:43
string Prefix
Prefix of the element. If not defined, the prefix will be an empty string.
Definition XmlElement.cs:31
XmlDocument TransformToDocument()
Transforms this custom XmlElement (and its children) into a standard XmlDocument.
IEnumerable< XmlElement > FindChildElementsByName(string name)
Method to find XML child elements, based of its name. Name space and hierarchy is not considered as e...
Dictionary< string, string > PrefixNameSpaceMap
Map of prefixes and corresponding name space URIs of this element.
Definition XmlElement.cs:47
IEnumerable< XmlElement > FindChildElementsByNameAndAttribute(string elementName, string attributeName, string attributeValue)
Method to find XML child elements, based of its name, an attribute name and value....
string InnerValue
Gets or set the inner value of the element.
Definition XmlElement.cs:53
List< XmlElement > Children
List of child elements. If none, the list is null.
Definition XmlElement.cs:39
IEnumerable< XmlElement > FindChildElementsByNameAndAttribute(string elementName, string attributeName)
Method to find XML child elements, based of its name, an attribute name. Name space and hierarchy is ...