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