Files
GenericTeProgramLibrary/Source/Program/Common/Lib/XmlDocumentWrapper.cs
2025-10-24 15:18:11 -07:00

238 lines
7.4 KiB
C#

/*-------------------------------------------------------------------------
// UNCLASSIFIED
/*-------------------------------------------------------------------------
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
COMPANY.
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
GOVERNMENT.
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
-------------------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
namespace ProgramLib
{
/// <summary>
/// A XML Wrapper class to create/modify XML files
/// </summary>
internal class XmlDocumentWrapper
{
public enum AddNodePosition
{
First,
Last
}
private XmlDocument _xmlDoc = null;
private string _xmlFilePath = String.Empty;
private object _syncObj = new object();
/// <summary>
/// Constructor
/// </summary>
/// <param name="xmlFilePath">XML file path</param>
/// <param name="rootNodeName">name of the root node.</param>
public XmlDocumentWrapper(string xmlFilePath, string rootNodeName = "root")
{
_xmlFilePath = xmlFilePath;
CreateXmlDocument(rootNodeName);
_xmlDoc = new XmlDocument();
_xmlDoc.Load(xmlFilePath);
}
/// <summary>
/// Create XML document if it doesn't exist
/// </summary>
private void CreateXmlDocument(string rootNodeName)
{
if (!File.Exists(_xmlFilePath))
{
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement(rootNodeName);
doc.AppendChild(root);
using (TextWriter sw = new StreamWriter(_xmlFilePath, false, Encoding.UTF8))
{
doc.Save(sw);
}
}
}
/// <summary>
/// Save XML document to file
/// </summary>
public void SaveToFile()
{
lock (_syncObj)
{
using (TextWriter sw = new StreamWriter(_xmlFilePath, false, Encoding.UTF8))
{
_xmlDoc.Save(sw);
}
}
}
/// <summary>
/// Add a node defined by {path}
/// </summary>
/// <param name="path">example: /root/node1/node2</param>
/// <param name="attributesDict">a dictionary of [name,value] pairs</param>
/// <param name="innerText">text of the node</param>
public void AddNode(string path, Dictionary<string, string> attributesDict = null, string innerText = null, AddNodePosition addNodePosition = AddNodePosition.Last)
{
lock (_syncObj)
{
XmlElement elem = (XmlElement)MakeXPath(_xmlDoc, path, addNodePosition);
if (!String.IsNullOrEmpty(innerText))
elem.InnerText = innerText;
if (attributesDict != null)
{
List<XmlAttribute> attributes = new List<XmlAttribute>();
foreach (KeyValuePair<string, string> item in attributesDict)
{
XmlAttribute attr = _xmlDoc.CreateAttribute(item.Key);
attr.Value = item.Value;
attributes.Add(attr);
}
SetAttrSafe(elem, attributes.ToArray());
}
}
}
/// <summary>
/// Remove a node
/// </summary>
public void RemoveNode(XmlNode node)
{
lock (_syncObj)
{
node.ParentNode.RemoveChild(node);
}
}
/// <summary>
/// Change attributes and/or inner text of an existing node
/// </summary>
public void ChangeNode(XmlNode node, Dictionary<string, string> attributesDict = null, string innerText = null)
{
lock (_syncObj)
{
if (!String.IsNullOrEmpty(innerText))
node.InnerText = innerText;
if (attributesDict != null)
{
List<XmlAttribute> attributes = new List<XmlAttribute>();
foreach (KeyValuePair<string, string> item in attributesDict)
{
XmlAttribute attr = _xmlDoc.CreateAttribute(item.Key);
attr.Value = item.Value;
attributes.Add(attr);
}
SetAttrSafe(node, attributes.ToArray());
}
}
}
/// <summary>
/// Get the first node in {path}
/// Useful for iterating through the sibling nodes to find the node with a specific attribute so we can modify the node
/// </summary>
/// <param name="path">example: /root/node1/node2</param>
public XmlNode GetNode(string path)
{
lock (_syncObj)
{
return _xmlDoc.SelectSingleNode(path);
}
}
/// <summary>
/// Get all the nodes matching the path
/// Useful for iterating through the matched nodes
/// </summary>
/// <param name="path">example: /root/node1/node2</param>
public XmlNodeList GetNodes(string path)
{
lock (_syncObj)
{
return _xmlDoc.SelectNodes(path);
}
}
/// <summary>
/// Set attribute
/// </summary>
private void SetAttrSafe(XmlNode node, XmlAttribute[] attrList)
{
foreach (var attr in attrList)
{
if (node.Attributes[attr.Name] != null)
{
node.Attributes[attr.Name].Value = attr.Value;
}
else
{
node.Attributes.Append(attr);
}
}
}
/// <summary>
/// Add a node using {xpath}
/// </summary>
/// <param name="xpath">example: /root/node1/node2</param>
private XmlNode MakeXPath(XmlDocument doc, string xpath, AddNodePosition addNodePosition)
{
return MakeXPath(doc, doc as XmlNode, xpath, addNodePosition);
}
/// <summary>
/// Iterate through each node in {xpath} and create them
/// </summary>
private XmlNode MakeXPath(XmlDocument doc, XmlNode parent, string xpath, AddNodePosition addNodePosition)
{
// grab the next node name in the xpath; or return parent if empty
string[] partsOfXPath = xpath.Trim('/').Split('/');
string nextNodeInXPath = partsOfXPath.First();
if (string.IsNullOrEmpty(nextNodeInXPath))
return parent;
// get or create the node from the name
XmlNode node = parent.SelectSingleNode(nextNodeInXPath);
if (partsOfXPath.Length == 1)
{
if (addNodePosition == AddNodePosition.Last)
node = parent.AppendChild(doc.CreateElement(nextNodeInXPath));
else
node = parent.PrependChild(doc.CreateElement(nextNodeInXPath));
}
// rejoin the remainder of the array as an xpath expression and recurse
string rest = String.Join("/", partsOfXPath.Skip(1).ToArray());
return MakeXPath(doc, node, rest, addNodePosition);
}
}
}