C#复杂XML反序列化为实体对象两种方式
阅读原文时间:2022年04月02日阅读:2

  今天主要讲的是如何把通过接口获取到的Xml数据转换成(反序列化)我们想要的实体对象,当然Xml反序列化和Json反序列化的方式基本上都是大同小异。都是我们事先定义好对应的对应的Xml实体模型,不过Xml是通过XmlSerializer类的相关特性来对实体对象和 XML文档之间进行序列化和反序列化操作的。序列化和反序列化其实都还好,我们可以调用封装好的XmlHelper帮助类即可实现,最关键的是我们该如何去定义这些实体模型(Model)。当你遇到对方接口一下子返回一大串的Xml数据并且里面存在很多不同的Xml节点,你该怎么办一个一个去解析这些节点到模型上去吗?本文我主要讲两种方式,第一种方法是通过手写的方式去定义Xml的实体对象模型类,第二种方法是通过Visual Studio自带的生成Xml实体对象模型类。

注意:以下是我稍微简化的Xml数据,实际数据可能比这里要复杂个大几倍。


successfuly 20211216081218

当然假如你有耐心、时间充足并且眼睛好的话可以使用这种手写的方式去定义,很多情况写到最好都会把自己给写糊涂了(可能是我年纪大了的原因)。

namespace Practices.Models
{
///

/// Envelope ///
[XmlType(TypeName = "envelope")]
public class CityDataModel
{
/// /// header ///
[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; }

}  

}

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;  
        }  
    }  
}

}

    /// <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);  
        }  
    }

https://www.cnblogs.com/Can-daydayup/p/16036872.html

https://www.cnblogs.com/Can-daydayup/p/16058817.html

https://www.cnblogs.com/Can-daydayup/p/16052873.html