最近项目中用到了博通PLC采集图像数据保存的业务,需要解析软件返回的xml文件,然后保存到数据库。
为了方便就自己整了一个xml转换为对应实体类的一个工具,减少去对应xml一个个创建实体类的繁琐工作量。
先来个操作演示。
实体类:
原理:其实xml转换实体类就是xml节点对应实体类,规则如下:
xml节点对应类;
xml节点里面的属性,对应实体类的属性;
xml子节点为xml父节点的属性;
如果一个节点的子节点数量不同,则已最多的一个为准进行创建类,如<result><label>Pass</label></result> 和 <result><label>Pass</label><id>0</id></result> 则以后面包含id的这个为准;
如果一个子节点在同一节点出现多次,则此节点在父节点上属性类型为List,反之一般为string(注意这里不能为IList,否则解析的时候会出问题,原因:List<T>是想创建一个List<T>的实例,并且需要使用到List<T>的功能,进行相关操作;而IList<T>只是想创建一个基于接口IList<T>的对象的实例,只是这个接口是由List<T>实现的。所以它只是希望使用到IList<T>接口规定的功能而已。);
如果一个节点下面没有子节点也没有属性,则此节点只为父节点的属性,不用创建类。
类上标记[XmlRoot]特性,属性上标记[XmlAttribute],子节点上标记[XmlElement]。
一、创建一个Winform 工程,设计页面如下:
其中命名空间为生成实体类的命名空间。
窗体代码如下:
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Linq; using System.Xml.Serialization; namespace XmlFormApp { public partial class Form1 : Form { public Form1() { InitializeComponent(); } /// <summary> /// 选择xml文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void iconTargetFilePath_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.InitialDirectory = "c:\\"; openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"; openFileDialog1.FilterIndex = 2; openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { this.TargetFilePath.Text = openFileDialog1.FileName; this.richTextBox.Text = File.ReadAllText(openFileDialog1.FileName); this.iconButtonCreate.Enabled = true; this.iconButtonView.Enabled = true; } } private void CreateClass(string path) { StringBuilder builder = new StringBuilder(); string classPath = "../../ClassFile.txt"; builder.Append(File.ReadAllText(classPath)); builder.Replace("{namespace}", textBoxClass.Text); StringBuilder classTxt = new StringBuilder(); classTxt.Append($"\r\n\t/// <summary>\r\n\t///实体类\r\n\t/// </summary>"); try { XElement element = XElement.Load(path); //子节点类集合 List<string> classList = new List<string>(); Dictionary<string, int> classAttrCountDic = new Dictionary<string, int>(); foreach (var item in element.DescendantsAndSelf()) { Dictionary<string, StringBuilder> itemDics = new Dictionary<string, StringBuilder>(); var _calss = classList.Where(o => o == item.Name.ToString()).FirstOrDefault(); var _classAttr = classAttrCountDic.Where(o => o.Key == item.Name.ToString() && o.Value != item.Elements().Count()).FirstOrDefault(); StringBuilder classTxt1 = new StringBuilder(); if (item.Elements().Count() == 0) { classList.Add(item.Name.ToString()); if (_calss != null) { continue; } //如果此节点下没有属性则直接跳过 if (item.Attributes().Count() == 0) { StringBuilder childTxt = new StringBuilder(); childTxt.Append("\r\n\t\t[XmlElement(").Append($@"""{item.Name.ToString()}"")]"); childTxt.Append($"\r\n\t\tpublic string {item.Name.ToString()}"); childTxt.Append(" { get; set; }"); classTxt1.Append("\r\n\t\t{").Append(item.Name.ToString()).Append("}"); itemDics.Add(item.Name.ToString(), childTxt); continue; } //没有子节点了 classTxt1.Append("\r\n\t[XmlRoot(").Append($@"""{item.Name.ToString()}"")]"); classTxt1.Append($"\r\n\tpublic class {item.Name.ToString()}"); classTxt1.Append("\r\n\t{"); //classList.Add(item.Name.ToString()); //创建该节点对应的属性 if (item.Attributes().Count() > 0) { foreach (var itemAttr in item.Attributes()) { classTxt1.Append("\r\n\t\t[XmlAttribute(").Append($@"""{itemAttr.Name.ToString()}"")]"); classTxt1.Append($"\r\n\t\tpublic string {itemAttr.Name}"); classTxt1.Append(" { get; set; }"); } } classTxt1.Append("\r\n\t}"); } else { if (_calss != null) { if (_classAttr.Key != null) { //返回先前创建类在字符串中的位置 int indexStr = classTxt.ToString().IndexOf($@"[XmlRoot(""{item.Name.ToString()}"")]"); StringBuilder itemStr = new StringBuilder(); itemStr.Append("\r\n\t"); itemStr.Append($@"[XmlRoot(""{item.Name.ToString()}"")]"); int i = 0; while (true) { string lenStr = classTxt.ToString(indexStr + ($@"[XmlRoot(""{item.Name.ToString()}"")]").Length + i, 1); i = i + 1; itemStr.Append(lenStr); if (itemStr.ToString().Contains("\r\n\t}")) { break; } } classTxt.Replace(itemStr.ToString(), null); classList.Remove(item.Name.ToString()); classAttrCountDic.Remove(item.Name.ToString()); } else { continue; } } classList.Add(item.Name.ToString()); classAttrCountDic.Add(item.Name.ToString(), item.Elements().Count()); //创建该节点对应的类 classTxt1.Append("\r\n\t[XmlRoot(").Append($@"""{item.Name.ToString()}"")]"); classTxt1.Append($"\r\n\tpublic class {item.Name.ToString()}"); classTxt1.Append("\r\n\t{"); //创建该节点子节点对应的类 foreach (var itemElement in item.Elements()) { StringBuilder childTxt = new StringBuilder(); var itemElementDic = itemDics.Where(o => o.Key == itemElement.Name.ToString()); if (itemElementDic.Count() > 0) { childTxt.Append("\r\n\t\t[XmlElement(").Append($@"""{itemElement.Name.ToString()}"")]"); childTxt.Append($"\r\n\t\tpublic List<{itemElement.Name.ToString()}> {itemElement.Name.ToString()}"); childTxt.Append(" { get; set; }"); itemDics.Remove(itemElement.Name.ToString()); itemDics.Add(itemElement.Name.ToString(), childTxt); } else { if (itemElement.Elements().Count() == 0) { childTxt.Append("\r\n\t\t[XmlElement(").Append($@"""{itemElement.Name.ToString()}"")]"); childTxt.Append($"\r\n\t\tpublic string {itemElement.Name.ToString()}"); childTxt.Append(" { get; set; }"); classTxt1.Append("\r\n\t\t{").Append(itemElement.Name.ToString()).Append("}"); itemDics.Add(itemElement.Name.ToString(), childTxt); } else { childTxt.Append("\r\n\t\t[XmlElement(").Append($@"""{itemElement.Name.ToString()}"")]"); childTxt.Append($"\r\n\t\tpublic {itemElement.Name.ToString()} {itemElement.Name.ToString()}"); childTxt.Append(" { get; set; }"); classTxt1.Append("\r\n\t\t{").Append(itemElement.Name.ToString()).Append("}"); itemDics.Add(itemElement.Name.ToString(), childTxt); } } } if (item.Name == "result") { } //创建该节点对应的属性 if (item.Attributes().Count() > 0) { foreach (var itemAttr in item.Attributes()) { classTxt1.Append("\r\n\t\t[XmlAttribute(").Append($@"""{itemAttr.Name.ToString()}"")]"); classTxt1.Append($"\r\n\t\tpublic string {itemAttr.Name}"); classTxt1.Append(" { get; set; }"); } } classTxt1.Append("\r\n\t}"); } classTxt.Append(classTxt1); foreach (var itemDic in itemDics) { classTxt.Replace("{" + itemDic.Key + "}", itemDic.Value.ToString()); } } //foreach (var itemDic in itemDics) //{ // classTxt.Replace("{" + itemDic.Key + "}", itemDic.Value.ToString()); //} builder.Replace("{classTxt}", classTxt.ToString()); this.richTextBox1.Text = builder.ToString(); } catch (Exception ex) { MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// <summary> /// 预览 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void iconButtonView_Click(object sender, EventArgs e) { string path = this.TargetFilePath.Text; if (string.IsNullOrEmpty(textBoxClass.Text)) { MessageBox.Show("请输入命名空间", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } CreateClass(path); iconButtonCheck.Enabled = true; } /// <summary> /// 生成 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void iconButtonCreate_Click(object sender, EventArgs e) { try { SaveFileDialog sfd = new SaveFileDialog(); //设置文件类型 sfd.Filter = "类|*.cs"; //设置默认文件类型显示顺序 sfd.FilterIndex = 1; //保存对话框是否记忆上次打开的目录 sfd.RestoreDirectory = true; //点了保存按钮进入 if (sfd.ShowDialog() == DialogResult.OK) { string localFilePath = sfd.FileName.ToString(); //获得文件路径 string fileNameExt = localFilePath.Substring(localFilePath.LastIndexOf("\\") + 1); //获取文件名,不带路径 //创建写入文件 FileStream fs1 = new FileStream(localFilePath, FileMode.Create, FileAccess.Write); StreamWriter sw = new StreamWriter(fs1); sw.WriteLine(this.richTextBox1.Text);//开始写入值 sw.Close(); fs1.Close(); MessageBox.Show("生成成功", "成功", MessageBoxButtons.OK, MessageBoxIcon.None); } } catch (Exception ex) { MessageBox.Show("生成失败" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// <summary> /// 效验 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void iconButton1_Click(object sender, EventArgs e) { try { var a = DeserializeToObject<root>(this.richTextBox.Text); string json = JsonConvert.SerializeObject(a); MessageBox.Show("效验成功", "成功", MessageBoxButtons.OK, MessageBoxIcon.None); } catch (Exception ex) { MessageBox.Show("效验失败" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// <summary> /// 将XML字符串反序列化为对象 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="xml">XML字符</param> /// <returns></returns> public T DeserializeToObject<T>(string xml) { T myObject; XmlSerializer serializer = new XmlSerializer(typeof(T)); StringReader reader = new StringReader(xml); myObject = (T)serializer.Deserialize(reader); reader.Close(); return myObject; } private void Form1_Resize(object sender, EventArgs e) { this.panel.Width = (this.panelCenter.Width - 20) / 2; this.panel2.Width = (this.panelCenter.Width - 20) / 2; } private void Form1_Load(object sender, EventArgs e) { this.panel.Width = (this.panelCenter.Width - 20) / 2; this.panel2.Width = (this.panelCenter.Width - 20) / 2; } } }
源代码地址:https://download.tnblog.net/resource/index/43db1228dbed4eb9904a4099f4e56e42