using Abp.Logging; using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Text; using System.Xml; namespace VberZero.Tools.FileHelpers; public static class XmlHelper { /// /// XML转换成DataTable /// /// /// public static string ConvertDataTableToXML(this DataTable xmlDS) { XmlTextWriter writer = null; try { var stream = new MemoryStream(); writer = new XmlTextWriter(stream, Encoding.UTF8); xmlDS.WriteXml(writer); int count = (int)stream.Length; byte[] arr = new byte[count]; stream.Seek(0, SeekOrigin.Begin); stream.Read(arr, 0, count); UTF8Encoding utf = new UTF8Encoding(); return utf.GetString(arr).Trim(); } catch (Exception e) { LogHelper.LogException(e); return ""; } finally { writer?.Close(); } } /// /// XML转换成DataTable /// /// /// public static DataSet ConvertXMLToDataSet(this string xmlData) { XmlTextReader reader = null; try { DataSet xmlDS = new DataSet(); var stream = new StringReader(xmlData); reader = new XmlTextReader(stream); xmlDS.ReadXml(reader); return xmlDS; } catch (Exception e) { LogHelper.LogException(e); return null; } finally { reader?.Close(); } } } /// /// Object mapping of a xml file /// public class XModel { /// /// Directory of this xml file /// public string XmlDirectory { get; set; } /// /// Xml file name /// public string FileName { get; set; } /// /// Xml file encode /// public string Encode { get; set; } /// /// Root tag /// public XmlTag Root { get; set; } /// /// XmlDocument object of this xml file /// private XmlDocument XmlDoc { get; set; } #region constructor /// /// Default constructor /// public XModel() { } /// /// Constructor: Create XmlModel from XmlTag and save xml file /// /// directory /// fileName /// encode type /// root tag public XModel(string directory, string fileName, string encode, XmlTag root) { CreateWithFile(directory, fileName, encode, root); } /// /// Constructor: Create XmlModel from XmlTag only /// /// root tag public XModel(XmlTag root) { CreateWithOutFile(root); } /// /// Constructor: Read XmlModel From xml file /// /// directory /// fileName public XModel(string directory, string fileName) { Read(directory, fileName); } /// /// Constructor: Read XmlModel From xml string /// /// xml string public XModel(string xml) { Read(xml); } #endregion constructor #region Create and Read XmlModel /// /// Create XmlModel from XmlTag and save xml file /// /// directory /// fileName /// encode type /// root tag public void CreateWithFile(string directory, string fileName, string encode, XmlTag root) { XmlDirectory = directory; FileName = fileName; Encode = encode; Root = root; Save(); } /// /// Create XmlModel from XmlTag only /// /// public void CreateWithOutFile(XmlTag root) { Root = root; } /// /// Read XmlModel From xml file /// /// directory /// fileName public void Read(string directory, string fileName) { XmlDirectory = directory; FileName = fileName; XmlDoc = new XmlDocument(); XmlDoc.Load(directory + fileName); Root = NodeToTag(XmlDoc.DocumentElement); } /// /// Read XmlModel From xml string /// /// xml string public void Read(string xml) { XmlDoc = new XmlDocument(); XmlDoc.LoadXml(xml); Root = NodeToTag(XmlDoc.DocumentElement); } #endregion Create and Read XmlModel /// /// Get current XmlModel's XmlDocument type object /// /// public XmlDocument GetXmlDocument() { //create XmlModel xmldoc is null if (XmlDoc == null) { XmlDoc = new XmlDocument(); } //replace root if (XmlDoc.DocumentElement != null) { XmlDoc.RemoveChild(XmlDoc.DocumentElement); } XmlDoc.AppendChild(TagToNode(Root)); //add or edit declaration if (XmlDoc.FirstChild is XmlDeclaration declaration) { if (!string.IsNullOrEmpty(Encode)) { declaration.Encoding = Encode; } } else { if (string.IsNullOrEmpty(Encode)) { throw new Exception("Encode can't be empty"); } XmlDoc.InsertBefore(XmlDoc.CreateXmlDeclaration("1.0", Encode, ""), XmlDoc.FirstChild); } return XmlDoc; } /// /// Save Object to file /// XmlDirectory and FileName and Encode need to be set before save /// public void Save() { if (Root == null) { throw new Exception("Root can't be null"); } if (string.IsNullOrEmpty(XmlDirectory) || string.IsNullOrEmpty(FileName)) { throw new Exception("XmlDirectory and FileName need to be set before save"); } //generate xmldocument GetXmlDocument(); if (!Directory.Exists(XmlDirectory)) { Directory.CreateDirectory(XmlDirectory); } XmlDoc.Save(XmlDirectory + FileName); } /// /// Delete file /// public void Delete() { if (File.Exists(XmlDirectory + FileName)) { File.Delete(XmlDirectory + FileName); } } /// /// Get xml string /// /// public override string ToString() { return GetXmlDocument().OuterXml; } #region Helper /// /// Recurtion transfer XmlNode into XmlTag /// /// XmlNode /// public XmlTag NodeToTag(XmlNode node) { //不转化注释 for (int i = 0; i < node.ChildNodes.Count; i++) { if (node.ChildNodes[i].Name == ("#comment")) { node.RemoveChild(node.ChildNodes[i]); } } //判断当前节点类型返回对应类型节点 if (node.ChildNodes.Count > 0 && node.FirstChild.NodeType != XmlNodeType.Text) { XmlChildTag childTag = new XmlChildTag(node.Name); //属性不为空添加属性 if (node.Attributes != null) { foreach (XmlAttribute attr in node.Attributes) { childTag.Attrs.Add(attr.Name, attr.Value); } } //递归添加子节点 foreach (XmlNode childNode in node.ChildNodes) { XmlTag tag = NodeToTag(childNode); if (tag is XmlChildTag xmlChildTag)//根据子节点类型加入对应列表 { childTag.ChildTagList.Add(xmlChildTag); } else { childTag.BaseTagList.Add(tag as XmlBaseTag); } } return childTag; } else { XmlBaseTag baseTag = new XmlBaseTag(node.Name); //属性不为空添加属性 if (node.Attributes != null) { foreach (XmlAttribute attr in node.Attributes) { baseTag.Attrs.Add(attr.Name, attr.Value); } } baseTag.InnerText = node.InnerText; return baseTag; } } /// /// Recurtion transfer XmlTag into XmlNode /// /// XmlTag /// public XmlNode TagToNode(XmlTag tag) { XmlNode node = XmlDoc.CreateElement(tag.Name); foreach (var attr in tag.Attrs) { XmlAttribute xmlAttr = XmlDoc.CreateAttribute(attr.Key); xmlAttr.Value = attr.Value; node.Attributes?.Append(xmlAttr); } if (tag is XmlChildTag childTag) { if (childTag.BaseTagList.Count == 0 && childTag.ChildTagList.Count == 0) { throw new Exception("A XmlChildTag " + childTag.Name + "'s BaseTagList and ChildTagList can't both empty,if this tag don't have any child please use XmlBaseTag type"); } //添加对应的子节点 foreach (XmlBaseTag innerTag in childTag.BaseTagList) { node.AppendChild(TagToNode(innerTag)); } foreach (XmlChildTag innerTag in childTag.ChildTagList) { node.AppendChild(TagToNode(innerTag)); } } else { if (tag is XmlBaseTag baseTag) node.InnerText = baseTag.InnerText; } return node; } /// /// Quickly get a XmlChildTag /// /// tag's name input by order /// public XmlChildTag GetChildTag(params string[] tagNames) { if (tagNames[0] != Root.Name) { throw new Exception("Root tag doesn't match"); } if (!(Root is XmlChildTag)) { throw new Exception("Root " + tagNames[0] + " must be XmlChildTag type"); } XmlChildTag result = (XmlChildTag)Root; for (int i = 1; i < tagNames.Length; i++) { if (result != null && result.ChildTagList.All(t => t.Name != tagNames[i])) { throw new Exception("Can't find XmlChildTag tag " + tagNames[i] + " by the input tag names with this order"); } result = result?.ChildTagList.FirstOrDefault(t => t.Name == tagNames[i]); } return result; } /// /// Quickly get a XmlBaseTag /// /// 按顺序输入的节点名称/tag's name input by order /// public XmlBaseTag GetBaseTag(params string[] tagNames) { if (tagNames[0] != Root.Name) { throw new Exception("Root tag doesn't match"); } if (Root is XmlBaseTag tag) { if (tagNames.Length == 1) { return tag; } throw new Exception("Root " + tagNames[0] + " is XmlBaseTag type, don't have any childs"); } XmlChildTag childTag = Root as XmlChildTag; for (int i = 1; i < tagNames.Length; i++) { if (childTag != null && (childTag.ChildTagList.All(t => t.Name != tagNames[i]) && childTag.BaseTagList.All(t => t.Name != tagNames[i]))) { throw new Exception("Can't find XmlTag " + tagNames[i] + " by the input tag names with this order"); } //最后一个节点查找BaseTagList,否则查找ChildTagList if (i == tagNames.Length - 1) { if (childTag != null && childTag.BaseTagList.Any(t => t.Name == tagNames[i])) { return childTag.BaseTagList.FirstOrDefault(t => t.Name == tagNames[i]); } throw new Exception("Tag:" + tagNames[i] + " must be XmlBaseTag type"); } //找到对应XmlChildTag节点缩小查找范围 if (childTag != null && childTag.ChildTagList.Any(t => t.Name == tagNames[i])) { childTag = childTag.ChildTagList.FirstOrDefault(t => t.Name == tagNames[i]); } else { throw new Exception("Tag:" + tagNames[i] + " must be XmlChildTag type"); } } return null; } #endregion Helper } /// /// XmlTag: A xml tag /// public abstract class XmlTag { /// /// Name /// public string Name { get; set; } /// /// Attributes /// public Dictionary Attrs { get; set; } } /// /// XmlChildTag: A XmlTag that at least have a XmlChildTag or XmlBaseTag inside /// public class XmlChildTag : XmlTag { /// /// XmlChildTags of this XmlChildTag /// public List ChildTagList { get; set; } /// /// XmlBaseTags of this XmlChildTag /// public List BaseTagList { get; set; } /// /// Constructor /// /// Tag's Name public XmlChildTag(string name) { Name = name; Attrs = new Dictionary(); ChildTagList = new List(); BaseTagList = new List(); } /// /// Get a XmlChildTag from this tag /// /// tag's name input by order /// public XmlChildTag GetChildTag(params string[] tagNames) { XmlChildTag result = this; foreach (var tagName in tagNames) { if (result != null && result.ChildTagList.All(t => t.Name != tagName)) { throw new Exception("Can't find XmlChildTag tag " + tagName + " by the input tag names with this order"); } result = result?.ChildTagList.FirstOrDefault(t => t.Name == tagName); } return result; } /// /// Get a XmlBaseTag from this tag /// /// tag's name input by order /// public XmlBaseTag GetBaseTag(params string[] tagNames) { XmlChildTag childTag = this; for (int i = 0; i < tagNames.Length; i++) { if (childTag != null && (childTag.ChildTagList.All(t => t.Name != tagNames[i]) && childTag.BaseTagList.All(t => t.Name != tagNames[i]))) { throw new Exception("Can't find XmlTag tag " + tagNames[i] + " by the input tag names with this order"); } //最后一个节点查找BaseTagList,否则查找ChildTagList if (i == tagNames.Length - 1) { if (childTag != null && childTag.BaseTagList.Any(t => t.Name == tagNames[i])) { return childTag.BaseTagList.FirstOrDefault(t => t.Name == tagNames[i]); } throw new Exception("Tag:" + tagNames[i] + " must be XmlBaseTag type"); } //找到对应XmlChildTag节点缩小查找范围 if (childTag != null && childTag.ChildTagList.Any(t => t.Name == tagNames[i])) { childTag = childTag.ChildTagList.FirstOrDefault(t => t.Name == tagNames[i]); } else { throw new Exception("Tag:" + tagNames[i] + " must be XmlChildTag type"); } } return null; } } /// /// Xml基础标签:基础标签内不能有子标签,可以有内部文字 /// XmlBaseTag:XmlBaseTag don't have child tag, but inner text /// public class XmlBaseTag : XmlTag { /// /// InnerText /// public string InnerText { get; set; } /// /// Constructor /// /// Tag's Name public XmlBaseTag(string name) { Name = name; Attrs = new Dictionary(); } } #region Test ////Create a xmlfile //public static void Create() //{ // XmlChildTag rootTag = new XmlChildTag("Root"); // rootTag.BaseTagList.Add(new XmlBaseTag("BaseTagOne")); // XModel myXModel = new XModel("D:\\XML\\", "MyXModel.xml", "utf-8", rootTag); // Console.WriteLine("Create success"); //} ////Read a xml file //public static void Read() //{ // XModel myXml = new XModel("D:\\XML\\", "MyXModel.xml"); // string rootName = myXml.Root.Name; // string baseTagOneName = (myXml.Root as XmlChildTag).BaseTagList.First().Name; // Console.WriteLine("Read success"); //} ////Edit a xml file //public static void Edit() //{ // XModel myXml = new XModel("D:\\XML\\", "MyXModel.xml"); // //edit root name and attributes // XmlChildTag root = myXml.Root as XmlChildTag; // root.Name = "NewRoot"; // root.Attrs.Add("attr1", "value1"); // //root add a child tag which have three base tag // XmlChildTag newChild = new XmlChildTag("NewChild"); // newChild.BaseTagList.Add(new XmlBaseTag("BaseTagTwo")); // XmlBaseTag baseTagThree = new XmlBaseTag("BaseTagThree"); // baseTagThree.Attrs.Add("testa", "testv"); // newChild.BaseTagList.Add(baseTagThree); // newChild.BaseTagList.Add(new XmlBaseTag("BaseTagFour") { InnerText = "some text" }); // root.ChildTagList.Add(newChild); // //save to file // myXml.Save(); // Console.WriteLine("Edit success"); //} ////Quickly Get and edit //public static void QuicklyGet() //{ // XModel myXml = new XModel("D:\\XML\\", "MyXModel.xml"); // //GetChildTag // XmlChildTag childA = myXml.GetChildTag("NewRoot", "NewChild"); // childA.Attrs.Add("find", "ture"); // //GetBaseTag // XmlBaseTag baseTagTwo = myXml.GetBaseTag("NewRoot", "NewChild", "BaseTagTwo"); // baseTagTwo.InnerText = "default return first tag be found"; // //quickly get tag from a XmlChildTag // XmlChildTag childB = myXml.GetChildTag("NewRoot", "NewChild"); // //lambda // XmlBaseTag target = childB.BaseTagList.Where(b => b.Attrs.Keys.Contains("testa")).First(); // target.InnerText = "quickly get combine with lambda let you read write xml file very quick"; // //continue quickly get // XmlBaseTag target2 = childB.GetBaseTag("BaseTagTwo"); // target2.InnerText = "quickly get can be use on XmlChildTag too."; // myXml.Save(); // Console.WriteLine("QuicklyGet success"); //} ////Delete //public static void Delete() //{ // XModel myXml = new XModel("D:\\XML\\", "MyXModel.xml"); // myXml.Delete(); // Console.WriteLine("Delete success"); //} ////To string //public static void PrintXModel() //{ // XModel myXml = new XModel("D:\\XML\\", "MyXModel.xml"); // Console.WriteLine(myXml.ToString()); //} ////Create from tag only //public static void CreateWithOutFile() //{ // XmlChildTag root = new XmlChildTag("root"); // root.BaseTagList.Add(new XmlBaseTag("base") { InnerText = "test" }); // XModel myXml = new XModel(root); // myXml.XmlDirectory = "d:\\"; // myXml.FileName = "nofile.xml"; // myXml.Encode = "utf-8"; // myXml.Save(); //} ////Read from xml String //public static void ReadXmlString() //{ // XModel newxml = new XModel(new XModel("D:\\XML\\", "MyXModel.xml").ToString()); // newxml.Root.Name = "newroot"; // newxml.XmlDirectory = "d:\\"; // newxml.FileName = "newxml.xml"; // newxml.Encode = "gbk"; // newxml.Save(); //} #endregion Test