虽然现在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,直接完成反序列化最终结果如下: