虽然现在json大行其道,但是xml格式依旧占据着广阔的编程世界,不管光伏锂电激光卫星汽车等等工业领域,基本上都是以xml为主,广大的.NET开发人员有很多被xml折磨的都要转java了,这篇小作文就来玩一种迅速完成xml到model的过程,让老板交代的任务能在5分钟解决,真正实现上班5分钟,摸鱼7小时。
本次要解析的XML格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<GCS Version="0x100"><ProjectInfo CfgUUID="5f2acfd0-aa91-49bb-a6d3-8f994810ffd5" ReduFlag="YES" UcpProtocol="1"ControllerType="33280" ProjectName="5201rddcwx" IPADDRA="172.20.1.2" IPADDRB="172.21.1.2" /><MemInfo><Area Size="131072" Index="0" Name="A" /><Area Size="131072" Index="1" Name="B" /></MemInfo><TagList><Tag Index="0" Name="MODULE1_TCPCmd0_VAR_OUT" Desc="" BitOffset="0" Offset="0"DataType="MODBUS_DT0" InitValue="OFF" AccessRight="ReadWrite" /><Tag Index="0" Name="MODULE1_TCPCmd1_VAR" Desc="" BitOffset="0" Offset="80"DataType="MODBUS_DT4" InitValue="OFF" AccessRight="ReadWrite" /></TagList><TagListSafety><Tag Index="0" Name="MODULE1_TCPCmd0_VAR_OUT" Desc="" UCPINDEX="2" BitOffset="0" Offset="0"DataType="INT" InitValue="OFF" AccessRight="ReadWrite" /><Tag Index="0" Name="MODULE1_TCPCmd1_VAR" Desc="" UCPINDEX="2" BitOffset="0" Offset="80"DataType="DWORD" InitValue="OFF" AccessRight="ReadWrite" /></TagListSafety><DataTypeList><Struct Size="4" Name="COM5002TCP_D" Desc=""><Element Name="DEVCFGSTATE" Desc="描述描述" BitOffset="1" Offset="0" DataType="BOOL" /><Element Name="DEVTYPESTATE" Desc="描述描述" BitOffset="2" Offset="0"DataType="BOOL" /><Element Name="COMMSTATE" Desc="描述描述" BitOffset="3" Offset="0" DataType="BOOL" /></Struct><Struct Size="40" Name="COM5002TCP_IN" Desc=""><Element Name="DEVCFGSTATE" Desc="描述描述" BitOffset="7"Offset="0" DataType="BOOL" /></Struct><Struct Size="128" Name="GCU5201_D" Desc=""><Element Name="KeyMode" Desc="描述描述" BitOffset="0" Offset="78" DataType="BYTE" /><Element Name="TIME" Desc="描述描述" BitOffset="0" Offset="0" DataType="TIME_FMT"><Element Name="TIME.YEAR" Desc="描述描述" BitOffset="0" Offset="0" DataType="BYTE" /><Element Name="TIME.MONTH" Desc="描述描述" BitOffset="0" Offset="1" DataType="BYTE" /></Element><Element Name="TimeServerDiag" Desc="描述描述" BitOffset="0" Offset="16"DataType="BYTE" /></Struct><Struct Size="24" Name="MODBUS_DT0" Desc=""><Element Name="VAR0" Desc="" BitOffset="0" Offset="12" DataType="INT" /><Element Name="VAR1" Desc="" BitOffset="0" Offset="14" DataType="INT" /><Element Name="VAR2" Desc="" BitOffset="0" Offset="16" DataType="INT" /><Element Name="VAR3" Desc="" BitOffset="0" Offset="18" DataType="INT" /><Element Name="VAR4" Desc="" BitOffset="0" Offset="20" DataType="INT" /></Struct><Struct Size="12" Name="MODBUS_DT2" Desc=""><Element Name="CommState" Desc="描述描述" BitOffset="4" Offset="0" DataType="BOOL" /></Struct><Struct Size="208" Name="MODBUS_DT4" Desc=""><Element Name="VAR0" Desc="" BitOffset="0" Offset="8" DataType="INT" /></Struct><Struct Size="4" Name="POINTER" Desc="" /><Struct Size="8" Name="TIME_FMT" Desc="STR_GC_CI_DATATYPE_TIME_FMT_DESC"><Element Name="YEAR" Desc="骞" BitOffset="0" Offset="0" DataType="BYTE" /></Struct><Struct Size="64" Name="_SEND_CMD" Desc=""><Element Name="pIN" Desc="STR_SC_AUX_SEND_CMD_INPUT_pIN" BitOffset="0" Offset="0"DataType="DWORD" /></Struct><Array Size="256" Name="GCU5201_D[2]" ElementDataType="GCU5201_D" ElementNum="2" /></DataTypeList>
</GCS>
可以看到本次的xml都是XmlAttribute,此处可以借助 System.Xml这个类进行操作,先新建所有类:
[XmlRoot("GCS")]public class SuperConGCSInfo{[XmlElement("ProjectInfo")]public ProjectInfo ProInfo { get; set; }[XmlArray("MemInfo")][XmlArrayItem("Area")]public MemInfo[] MemInfos { get; set; }[XmlArray("TagList")][XmlArrayItem("Tag")]public Tags[] TagList { get; set; }[XmlArray("TagListSafety")][XmlArrayItem("Tag")]public Tags[] TagListSafety { get; set; }[XmlElement("DataTypeList")]public DataTypeList DataTypeList { get; set; }}public class DataTypeList{[XmlElement("Struct")]public Struct[] Struct { get; set; }[XmlElement("Array")]public Arrays[] Arrays { get; set; }}public class Arrays{[XmlAttribute("Size")]public string Size { get; set; }[XmlAttribute("Name")]public string Name { get; set; }[XmlAttribute("ElementDataType")]public string ElementDataType { get; set; }[XmlAttribute("ElementNum")]public string ElementNum { get; set; }}public class ProjectInfo{[XmlAttribute("CfgUUID")]public string CfgUUID { get; set; }[XmlAttribute("ReduFlag")]public string ReduFlag { get; set; }[XmlAttribute("UcpProtocol")]public string UcpProtocol { get; set; }[XmlAttribute("ControllerType")]public string ControllerType { get; set; }[XmlAttribute("ProjectName")]public string ProjectName { get; set; }[XmlAttribute("IPADDRA")]public string IPADDRA { get; set; }[XmlAttribute("IPADDRB")]public string IPADDRB { get; set; }}public class MemInfo{[XmlAttribute("Size")]public string Size { get; set; }[XmlAttribute("Index")]public string Index { get; set; }[XmlAttribute("Name")]public string Name { get; set; }}public class Tags{[XmlAttribute("Index")]public string Index { get; set; }[XmlAttribute("Name")]public string Name { get; set; }[XmlAttribute("Desc")]public string Desc { get; set; }[XmlAttribute("BitOffset")]public string BitOffset { get; set; }[XmlAttribute("Offset")]public string Offset { get; set; }[XmlAttribute("DataType")]public string DataType { get; set; }[XmlAttribute("InitValue")]public string InitValue { get; set; }[XmlAttribute("AccessRight")]public string AccessRight { get; set; }}public class Struct{[XmlAttribute("Size")]public string Size { get; set; }[XmlAttribute("Name")]public string Name { get; set; }[XmlElement("Element")]public Element[] Elements { get; set; }}public class Element{[XmlAttribute("Name")]public string Name { get; set; }[XmlAttribute("Desc")]public string Desc { get; set; }[XmlAttribute("BitOffset")]public string BitOffset { get; set; }[XmlAttribute("Offset")]public string Offset { get; set; }[XmlAttribute("DataType")]public string DataType { get; set; }[XmlElement("Element")]public Element[] Elements { get; set; }}
说明一下这里面的一些特性。
根节点(XmlRoot):
首先类中包含根节点(XmlRoot)GCS,跟节点是xml中最外层的包裹元素,C#中使用XmlRoot特性声明;
元素节点(XmlElement)
xml中任何一个节点,不知道怎么生命,其实都可以使用XmlElement,它是万能的。比如我们上面xml看到的ProjectInfo、DataTypeList等等包裹的节点都是;
数组(XmlArray):
数组节点一般情况下都是和XmlArrayItem搭配使用,比如MemInfo是数组,那XmlArrayItem就是Area,TagList对应的是Tag,TagListSafety对应也是Tag,这样一声明就非常清晰。c#中数组使用XmlArray、子类使用XmlArrayItem声明。
以上xml我们需要注意的是DataTypeList这个节点,DataTypeList可以使用XmlArray进行声明,但是如果一旦这样声明,就会导致Array读取失败,所以我这边单独又新建一个类DataTypeList,DataTypeList类里面又分别使用XmlElement声明一个Struct和Array,这样下去,就能正常读取了。
其实System.Xml里面有非常多的特性,比如枚举(XmlEnum),忽略(XmlIgnore)、包含(XmlInclude),纯文本(XmlText)、抽象类型(XmlType)等等,但是基本上不在特殊场合基本上用不到,其余的可以自行新建xml试试。
新建读取xml方法:
public T DeserializeFromXml<T>(string filePath){try{using (StreamReader reader = new StreamReader(filePath, Encoding.UTF8)){XmlSerializer xs = new XmlSerializer(typeof(T));T ret = (T)xs.Deserialize(reader);return ret;}}catch{return default(T);}}
使用文件上传方式读取xml:
var dialog = new OpenFileDialog{DefaultExt = "*.xml",AddExtension = true,Filter = "Import Files|*.xml",CheckPathExists = true};
if (dialog.ShowDialog() != true || string.IsNullOrEmpty(dialog.FileName) || !File.Exists(dialog.FileName))return;
SuperConGCSInfo beckhoffTagModel = superConVarConver.DeserializeFromXml<SuperConGCSInfo>(dialog.FileName);
以上方法读取xml速度块,能迅速生成一个Model,直接完成反序列化最终结果如下: