using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Xml; namespace JWH { public static class ExtensionXml { /// /// 이름으로 노드를 검색하여 첫번째 노드를 반환합니다. /// /// /// /// 하위검색 /// public static XmlNode GetSingleNodeByName(this XmlDocument sender, string name, bool fullScan = true) { try { foreach (XmlNode node in sender.ChildNodes) { if (string.Compare(node.Name, name, true) == 0) return node; } if (fullScan == false) return null; foreach (XmlNode node in sender.ChildNodes) { XmlNode result = node.GetSingleNodeByName(name); if (result != null) return result; } return null; } catch (Exception ex) { XLogger.Instance.Fatal(ex); return null; } } /// /// 이름으로 노드를 검색하여 첫번째 노드를 반환합니다. /// /// /// /// 하위검색 /// public static XmlNode GetSingleNodeByName(this XmlNode sender, string name, bool fullScan = true) { try { foreach (XmlNode node in sender.ChildNodes) { if (string.Compare(node.Name, name, true) == 0) return node; } if (fullScan == false) return null; foreach (XmlNode node in sender.ChildNodes) { XmlNode result = node.GetSingleNodeByName(name); if (result != null) return result; } return null; } catch (Exception ex) { XLogger.Instance.Fatal(ex); return null; } } /// /// 이름으로 노드를 검색하여 반환합니다. /// /// /// /// 하위검색 /// public static XmlNode[] GetNodesByName(this XmlDocument sender, string name, bool fullScan = true) { List nodes = new List(); try { foreach (XmlNode node in sender.ChildNodes) { if (string.Compare(node.Name, name, true) == 0) nodes.Add(node); } if (fullScan == false) return nodes.ToArray(); foreach (XmlNode node in sender.ChildNodes) { nodes.AddRange(node.GetNodesByName(name)); } return nodes.ToArray(); } catch (Exception ex) { XLogger.Instance.Fatal(ex); return null; } } /// /// 이름으로 노드를 검색하여 반환합니다. /// /// /// /// 하위검색 /// public static XmlNode[] GetNodesByName(this XmlNode sender, string name, bool fullScan = true) { List nodes = new List(); try { foreach (XmlNode node in sender.ChildNodes) { if (string.Compare(node.Name, name, true) == 0) nodes.Add(node); } if (fullScan == false) return nodes.ToArray(); foreach (XmlNode node in sender.ChildNodes) { nodes.AddRange(node.GetNodesByName(name)); } return nodes.ToArray(); } catch (Exception ex) { XLogger.Instance.Fatal(ex); return null; } } /// /// 경로를 검색하여 반환합니다. /// /// /// /// public static XmlNode[] GetNodesByPath(this XmlDocument sender, string path) { List nodes = new List(); List childs = new List(); try { string[] names = path.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries); foreach (XmlNode node in sender.ChildNodes) { if (string.Compare(node.Name, names[0], true) == 0) { if (names.Length > 1) childs.Add(node); else nodes.Add(node); } } StringBuilder sb = new StringBuilder(); for (int i = 1; i < names.Length; i++) sb.AppendFormat($"/{names[i]}"); foreach (XmlNode node in childs) { nodes.AddRange(node.GetNodesByPath(sb.ToString())); } return nodes.ToArray(); } catch (Exception ex) { XLogger.Instance.Fatal(ex); return null; } } /// /// 경로를 검색하여 반환합니다. /// /// /// /// public static XmlNode[] GetNodesByPath(this XmlNode sender, string path) { List nodes = new List(); List childs = new List(); try { string[] names = path.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries); foreach (XmlNode node in sender.ChildNodes) { if (string.Compare(node.Name, names[0], true) == 0) { if (names.Length > 1) childs.Add(node); else nodes.Add(node); } } StringBuilder sb = new StringBuilder(); for (int i = 1; i < names.Length; i++) sb.AppendFormat($"/{names[i]}"); foreach (XmlNode node in childs) { nodes.AddRange(node.GetNodesByPath(sb.ToString())); } return nodes.ToArray(); } catch (Exception ex) { XLogger.Instance.Fatal(ex); return null; } } /// /// 속성이 동일한 노드를 검색하여 반환한다. /// /// /// Name의 대/소문자 무시 /// Value의 대/소문자 무시 /// /// private static bool CheckAttributes(this XmlNode sender, bool ignorsCaseName = true, bool ignorsCaseValue = false, params KeyValuePair[] attributes) { try { foreach (KeyValuePair pair in attributes) { foreach (XmlAttribute attribute in sender.Attributes) { if (string.Compare(pair.Key, attribute.Name, ignorsCaseName) == 0) if (string.Compare(pair.Value, attribute.Value, ignorsCaseValue) == 0) continue; else return false; } } return true; } catch (Exception ex) { XLogger.Instance.Fatal(ex); return false; } } /// /// 노드의 속성을 검색한다 /// /// /// /// Attribute.Name 대/소문자 무시 /// public static XmlAttribute GetAttribute(this XmlNode sender, string name, bool ignorsCase = true) { if (sender == null || sender.Attributes == null) return null; foreach (XmlAttribute attribute in sender.Attributes) { if (string.Compare(attribute.Name, name, ignorsCase) == 0) return attribute; } return null; } /// /// 노드의 속성값을 반환한다 /// /// /// /// Attribute.Name 대/소문자 무시 /// public static string GetAttributeValue(this XmlNode sender, string name, bool ignorsCase = true) { if (sender == null) return null; foreach (XmlAttribute attribute in sender.Attributes) { if (string.Compare(attribute.Name, name, ignorsCase) == 0) return attribute.Value; } return null; } /// /// 노드의 속성값을 변경한다 /// /// /// /// /// Attribute.Name 대/소문자 무시 /// public static string SetAttributeValue(this XmlNode sender, string name, string value, bool ignorsCase = true) { foreach (XmlAttribute attribute in sender.Attributes) { if (string.Compare(attribute.Name, name, ignorsCase) == 0) { attribute.Value = value; return null; } } return null; } public static void PropertiesCopyAttribute(this XmlNode sender, object dest) { try { foreach (XmlAttribute attribute in sender.Attributes) dest.PropertySet(attribute.Name, attribute.Value); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } public static void PropertiesCopy(this XmlNode sender, object dest) { try { foreach (XmlNode node in sender.ChildNodes) dest.PropertySet(node.Name, node.InnerText); } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } public static string GetText(this XmlNode sender) { if (sender.ChildNodes.Count <= 0) return string.Empty; string rtnValue = null; foreach (XmlNode node in sender.ChildNodes) { if (node.GetType() == typeof(XmlText)) rtnValue = node.InnerText; } return rtnValue; } public static void SetText(this XmlNode sender, string value) { XmlNode nodeText = null; foreach (XmlNode node in sender.ChildNodes) { if (node.GetType() == typeof(XmlText)) { nodeText.InnerText = value; return; } } if (sender.ChildNodes.Count == 0) { sender.InnerText = value; } } /// /// XmlDocument 내용을 문자열로 반환합니다. /// /// /// /// /// public static string GetBeautify(this XmlDocument sender, int indent = 2, bool haeder = true) { try { string rtn = string.Empty; using (MemoryStream stream = new MemoryStream()) { XmlWriterSettings settings = new XmlWriterSettings { Encoding = new UTF8Encoding(false), Indent = true, IndentChars = "".PadLeft(indent), NewLineChars = Environment.NewLine, NewLineHandling = NewLineHandling.Replace, }; using (XmlWriter writer = XmlWriter.Create(stream, settings)) sender.Save(writer); rtn = Encoding.UTF8.GetString(stream.ToArray()); } if (haeder == false) { int index = rtn.IndexOf("= 0) { index = rtn.IndexOf("<", index + 1); rtn = rtn.Substring(index); } } return rtn; } catch (Exception ex) { throw ex; } } /// /// 노드를 XmlDocument에 복사합니다. /// /// /// /// public static void CopyValue(this XmlNode sender, XmlDocument document, bool isChild = true) { try { string path = sender.GetFullPath(); foreach (XmlNode child in sender.ChildNodes) { if (child.NodeType == XmlNodeType.Text) { XmlNode dest = document.SelectSingleNode(path); if (dest == null) continue; if (dest.ChildNodes.Count == 0) { XmlNode valueNode = document.CreateNode("text", "", ""); dest.AppendChild(valueNode); } foreach (XmlNode destChild in dest.ChildNodes) if (destChild.NodeType == XmlNodeType.Text) destChild.Value = child.Value; } else { if (isChild) child.CopyValue(document); } } } catch (Exception ex) { throw ex; } } /// /// 하위 노드를 생성하고 반환합니다. /// /// /// /// /// public static XmlNode CreateChildNode(this XmlNode sender, string name, string innerText = "", int index = -1, bool isAfter = true) { try { XmlDocument document = sender.OwnerDocument; XmlNode childNode = document.CreateElement(name); if (!string.IsNullOrEmpty(innerText)) childNode.InnerText = innerText; if (index < 0 || index > sender.ChildNodes.Count) { sender.AppendChild(childNode); return childNode; } XmlNode refNode = sender.ChildNodes[index]; if (isAfter) sender.InsertAfter(childNode, refNode); else sender.InsertBefore(childNode, refNode); return childNode; } catch (Exception ex) { throw ex; } } /// /// 노드를 삭제합니다. /// /// /// /// public static bool RemoveChildNode(this XmlNode sender, int index) { try { if (index >= sender.ChildNodes.Count) return false; XmlNode node = sender.ChildNodes[index]; if (node != null) sender.RemoveChild(node); return true; } catch (Exception ex) { throw ex; } } /// /// 노드를 삭제합니다. /// /// /// /// public static bool RemoveChildNode(this XmlNode sender, string name) { try { XmlNode node = sender.GetSingleNodeByName(name); if (node == null) return false; sender.RemoveChild(node); return true; } catch (Exception ex) { throw ex; } } /// /// 노드를 삭제합니다. /// /// /// /// public static bool RemoveChildNodes(this XmlNode sender, string name) { try { foreach (XmlNode node in sender.GetNodesByName(name)) sender.RemoveChild(node); return true; } catch (Exception ex) { throw ex; } } private static string GetFullPath(this XmlNode sender) { if (sender == null) return string.Empty; if (sender.ParentNode == null || sender.ParentNode.NodeType != XmlNodeType.Element) return $"//{sender.Name}"; return $"{sender.ParentNode.GetFullPath()}/{sender.Name}"; } /// /// 문자열에 있는 잘못된 XML 문자를 해당하는 올바른 XML로 바꿉니다. /// /// /// 잘못된 문자가 있었으나 바뀐 입력 문자열입니다. public static string XMLEscape(this string sender) { try { return System.Security.SecurityElement.Escape(sender); } catch { return sender; } } /// /// 입력 문자열에서 이스케이프된 문자를 변환합니다. /// /// /// public static string XMLUnescape(this string sender) { try { return System.Text.RegularExpressions.Regex.Unescape(sender); } catch { return sender; } } } }