前言
今天主要讲的是如何把通过接口获取到的Xml数据转换成(反序列化)我们想要的实体对象,当然Xml反序列化和Json反序列化的方式基本上都是大同小异。都是我们事先定义好对应的对应的Xml实体模型,不过Xml是通过XmlSerializer类的相关特性来对实体对象和 XML文档之间进行序列化和反序列化操作的。序列化和反序列化其实都还好,我们可以调用封装好的XmlHelper帮助类即可实现,最关键的是我们该如何去定义这些实体模型(Model)。当你遇到对方接口一下子返回一大串的Xml数据并且里面存在很多不同的Xml节点,你该怎么办一个一个去解析这些节点到模型上去吗?本文我主要讲两种方式,第一种方法是通过手写的方式去定义Xml的实体对象模型类,第二种方法是通过Visual Studio自带的生成Xml实体对象模型类。
需要操作的Xml数据
注意:以下是我稍微简化的Xml数据,实际数据可能比这里要复杂个大几倍。
<?xml version="1.0" encoding="utf-8" ?> <envelope> <header> <version port="1111" host="www.baidu.com">successfuly</version> <timestamp>20211216081218</timestamp> </header> <response type="cities" product="hotel"> <cities> <city> <code value="zg" /> <city_tax value="true" /> <names> <name language="fr" value="ABANO TERME - PADOUE" /> <name language="en" value="ABANO TERME - PADUE" /> <name language="nl" value="ABANO TERME - PADUE" /> </names> </city> <city> <code value="hk" /> <city_tax value="false" /> <names> <name language="fr" value="ABBADIA SAN SALVATORE - SIENNE" /> <name language="en" value="ABBADIA SAN SALVATORE - SIENA" /> <name language="nl" value="ABBADIA SAN SALVATORE - SIENA" /> </names> </city> </cities> </response> </envelope>
一、通过是手写的方式去定义Xml的实体对象模型类
当然假如你有耐心、时间充足并且眼睛好的话可以使用这种手写的方式去定义,很多情况写到最好都会把自己给写糊涂了(可能是我年纪大了的原因)。
namespace Practices.Models { /// <summary> /// Envelope /// </summary> [XmlType(TypeName = "envelope")] public class CityDataModel { /// <summary> /// header /// </summary> [XmlElement("header")] public Header header { get; set; } /// <summary> /// response /// </summary> [XmlElement("response")] public Response response { get; set; } } /// <summary> /// Header /// </summary> [XmlType(TypeName = "header")] public class Header { /// <summary> /// version /// </summary> [XmlElement("version")] public Version version { get; set; } /// <summary> /// timestamp /// </summary> [XmlElement("timestamp")] public string timestamp { get; set; } } /// <summary> /// Version /// </summary> public class Version { /// <summary> /// port /// </summary> [XmlAttribute("port")] public string port { get; set; } /// <summary> /// host /// </summary> [XmlAttribute("host")] public string host { get; set; } /// <summary> /// value:XmlTextAttribute指示该属性作为XML文本处理 /// </summary> [XmlTextAttribute()] public string value { get; set; } } /// <summary> /// Response /// </summary> [XmlType(TypeName = "response")] public class Response { /// <summary> /// type /// </summary> [XmlAttribute] public string type { get; set; } /// <summary> /// product /// </summary> [XmlAttribute] public string product { get; set; } /// <summary> /// cities /// </summary> [XmlArray("cities")] public List<City> cities { get; set; } } /// <summary> /// class: City /// </summary> [XmlType(TypeName = "city")] public class City { /// <summary> /// code /// </summary> [XmlElement("code")] public Code code { get; set; } /// <summary> /// city_tax /// </summary> [XmlElement("city_tax")] public City_tax city_tax { get; set; } /// <summary> /// names /// </summary> [XmlArray("names")] public List<Name> names { get; set; } } /// <summary> /// class: Code /// </summary> [XmlType(TypeName = "code")] public class Code { /// <summary> /// /// </summary> [XmlAttribute("value")] public string value { get; set; } } /// <summary> /// class: City_tax /// </summary> [XmlType(TypeName = "city_tax")] public class City_tax { /// <summary> /// /// </summary> [XmlAttribute("value")] public string value { get; set; } } /// <summary> /// class: Name /// </summary> [XmlType(TypeName = "name")] public class Name { /// <summary> /// /// </summary> [XmlAttribute("language")] public string language { get; set; } /// <summary> /// /// </summary> [XmlAttribute("value")] public string value { get; set; } } }
二、通过Visual Studio自带的生成Xml实体对象模型类
Vs被称为宇宙最强IDE也不是没有理由的,它集成了很多自动创建功能,如自动生成Json类、Xml类等,虽然说使用Vs自动生成的Xml模型可读性有点差并且有些冗余,但是快捷省事,只需要略微改动一下即可使用。
1、首先Ctrl+C复制你需要生成的Xml文档内容
2、找到编辑=》选择性粘贴=》将Xml粘贴为类
3、以下是使用VS自动生成的Xml类
namespace Practices.Models { // 注意: 生成的代码可能至少需要 .NET Framework 4.5 或 .NET Core/Standard 2.0。 /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] //TODO:注意这里因为我把类名改成了我自定义的,所以在TypeName这里需要声明Xml文档的节点名 [System.Xml.Serialization.XmlTypeAttribute(typeName: "envelope")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] public partial class NewCityDataModel { private envelopeHeader headerField; private envelopeResponse responseField; /// <remarks/> public envelopeHeader header { get { return this.headerField; } set { this.headerField = value; } } /// <remarks/> public envelopeResponse response { get { return this.responseField; } set { this.responseField = value; } } } /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class envelopeHeader { private envelopeHeaderVersion versionField; private ulong timestampField; /// <remarks/> public envelopeHeaderVersion version { get { return this.versionField; } set { this.versionField = value; } } /// <remarks/> public ulong timestamp { get { return this.timestampField; } set { this.timestampField = value; } } } /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class envelopeHeaderVersion { private ushort portField; private string hostField; private string valueField; /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public ushort port { get { return this.portField; } set { this.portField = value; } } /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public string host { get { return this.hostField; } set { this.hostField = value; } } /// <remarks/> [System.Xml.Serialization.XmlTextAttribute()] public string Value { get { return this.valueField; } set { this.valueField = value; } } } /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class envelopeResponse { private envelopeResponseCity[] citiesField; private string typeField; private string productField; /// <remarks/> [System.Xml.Serialization.XmlArrayItemAttribute("city", IsNullable = false)] public envelopeResponseCity[] cities { get { return this.citiesField; } set { this.citiesField = value; } } /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public string type { get { return this.typeField; } set { this.typeField = value; } } /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public string product { get { return this.productField; } set { this.productField = value; } } } /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class envelopeResponseCity { private envelopeResponseCityCode codeField; private envelopeResponseCityCity_tax city_taxField; private envelopeResponseCityName[] namesField; /// <remarks/> public envelopeResponseCityCode code { get { return this.codeField; } set { this.codeField = value; } } /// <remarks/> public envelopeResponseCityCity_tax city_tax { get { return this.city_taxField; } set { this.city_taxField = value; } } /// <remarks/> [System.Xml.Serialization.XmlArrayItemAttribute("name", IsNullable = false)] public envelopeResponseCityName[] names { get { return this.namesField; } set { this.namesField = value; } } } /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class envelopeResponseCityCode { private string valueField; /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public string value { get { return this.valueField; } set { this.valueField = value; } } } /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class envelopeResponseCityCity_tax { private bool valueField; /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public bool value { get { return this.valueField; } set { this.valueField = value; } } } /// <remarks/> [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class envelopeResponseCityName { private string languageField; private string valueField; /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public string language { get { return this.languageField; } set { this.languageField = value; } } /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public string value { get { return this.valueField; } set { this.valueField = value; } } } }
验证两个Xml类是否能够反序列化成功
/// <summary> /// 读取Xml文件内容反序列化为指定的对象 /// </summary> /// <param name="filePath">Xml文件的位置(绝对路径)</param> /// <returns></returns> public static T DeserializeFromXml<T>(string filePath) { try { if (!File.Exists(filePath)) throw new ArgumentNullException(filePath + " not Exists"); using (StreamReader reader = new StreamReader(filePath)) { XmlSerializer xs = new XmlSerializer(typeof(T)); T ret = (T)xs.Deserialize(reader); return ret; } } catch (Exception ex) { return default(T); } }