C# XML反序列化,及转换错误的解决方法(空值,数组等)

目录

转换方法

问题及解决

问题:数值类型为空时, 转换出错

问题:在转换带有列表的节点时识别错误(list,数组)

问题:在XML序列化时怎样判断 必填属性是否被填写

问题:当类赋值后,转换为xml的字符串中 节点多了xmlns属性

xml序列化时类的自定义属性

空值标识:IsNullable

指定序列化名称:ElementName

取消字段的正反序列化:[XmlIgnore]

转换方法

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
 
namespace WindowsFormsApplication1
{
    class XmlSerializeHelper
    {
        #region 使用演示
        //aaa  类名
        //Example 实例名
        //strxml xml字符串
        
        string strxml;
        //反序列化演示
        //aaa Example = XmlSerializeHelper.DESerializer<aaa>(strxml); 
        //序列化演示
        //string strxml = XmlSerializeHelper.XmlSerialize<aaa>(Example);
        #endregion
 
        /// <summary>
        /// 实体类转换成XML
        /// </summary>
        /// <typeparam name="T">类名</typeparam>
        /// <param name="obj">T类名的实例</param>
        /// <returns></returns>
        public static string XmlSerialize<T>(T obj)
        {
            using (StringWriter sw = new StringWriter())
            {
                Type t = obj.GetType();
                XmlSerializer serializer = new XmlSerializer(obj.GetType());
                serializer.Serialize(sw, obj);
                sw.Close();
                return sw.ToString();
            }
        }
        
 
 
 
        /// <summary>
        /// XML转换成实体类-方法1
        /// </summary>
        /// <typeparam name="T">对应的类</typeparam>
        /// <param name="strXML">XML字符串</param>
        /// <returns></returns>
        public static T DESerializer<T>(string strXML) where T : class
        {
            try
            {
                using (StringReader sr = new StringReader(strXML))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(T));
                    return serializer.Deserialize(sr) as T;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }
 
        /// <summary>
        /// XML转换成实体类-方法2
        /// </summary>
        /// <param name="xmlStr"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object DeserializeFromXml(string xmlStr, Type type)
        {
            try
            {
                using (StringReader sr = new StringReader(xmlStr))
                {
                    XmlSerializer xs = new XmlSerializer(type);
                    return xs.Deserialize(sr);
                }
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }
        //Request
        //
 
 
    }
}

小技巧:在建立xml对应类时可自动建立,方法如下:

将完整的XML文本复制下来
新建一个类,将光标放在准备粘贴的位置
点击VS左上角的 [编辑] - [选择性粘贴] - [将XML粘贴为类]

注:如果没有 [将xml粘贴为类] 的选项,右键  将 项目-属性-应用程序 中的目标框架改为.NET Framework 4.5 即可。(东经115注:若本来就是4.5,则需要安装组件,位置在菜单:工具>获取工具或功能>单个组件>Web开发工具和.NET Core)

问题及解决
问题:数值类型为空时, 转换出错

在转换后的实体类中,有些属性因为业务需求,需要修改类型为Int32,Uint32等数字类型,但是给出的xml文本中,此项可能会没有值,导致在反序列化时会出错(即使在get方法中容错也不行)

解决:因为在反序列化的时候接受的属性是数字类型且xml文本中为空,就会出错,无论是否在get方法中容错;所以用属性类型为string的属性进行反序列化的对接,具体容错和赋值可在该string类型内的get方法中进行(可赋值给其他数值类型属性,string类型属性仅当做反序列化时的对接口),具体操作如下
举例说明:反序列化的类中有属性int num 和 string str 两个属性

查看代码

//对应的实体类
public partial class aaa
    {
        public string str { get; set; }
 
        [XmlIgnore]//取消反序列化
        public int num;
 
        //用string类型的属性来反序列化,将值转赋给原数值属性num
        [XmlElement(ElementName = "num")]//反序列化对应的属性名
        public string numStr
        {
            get
            {
                return this.num.ToString();
            }
            set
            {
                Int32 num1;
                Int32.TryParse(value.ToString(), out num1);
                this.num = num1;
            }
        }
        
    }


注意:在XML反序列化中对应的类的属性必须为public才能被反序列化,private不能被反序列化

 

问题:在转换带有列表的节点时识别错误(list,数组)

解决:在列表标签下加2个及以上的子循环标签,进行转换时即可自动转换为数组
举例说明:转换对照

查看代码

<eee:qqq xmlns:rrr="http://rrr" xmlns:eee="http://eee">
  <eee:vvv>
    <!--重复1-->
    <eee:mmm />
    <!--重复2-->
    <eee:mmm />
  </eee:vvv>
</eee:qqq>
生成结果: 

/// <remarks/>
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://eee")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://eee", IsNullable = false)]
    public partial class qqq
    {
        private object[] vvvField;
 
        /// <remarks/>
        //public List<object> vvv { get; set; }
        [System.Xml.Serialization.XmlArrayItemAttribute("mmm", IsNullable = false)]
        public object[] vvv
        {
            get
            {
                return this.vvvField;
            }
            set
            {
                this.vvvField = value;
            }
        }
        
    }

 
问题:在XML序列化时怎样判断 必填属性是否被填写

解决:利用自定义属性和get方法,
1.将需要必填的类中属性添加 IsNullable = true 的自定义属性,当序列化为xml后,为null的属性的节点标签有 xsi:nil="true" 属性显示
2.将需要必填的类中属性的get方法中添加约束,如果value为空时添加标识
3.在序列化后的XML中查找指定的标识,即可判断必填属性是否都已填写
所需方法:

查看代码

/// <summary>
/// 检查是否存在必填项未填错误
/// </summary>
/// <param name="XmlStr">带有标识,从类中转换出的xml数据</param>
/// <param name="ErrorKeyword">指定错误标识</param>
/// <returns></returns>
private static bool IsRequiredItemError(string XmlStr, string ErrorKeyword)
{
    XDocument xmlDocument = XDocument.Parse(XmlStr);
    //查询指定空识别
    if (XmlStr.Contains(ErrorKeyword))
    {
        return true;
    }
    //遍历节点属性是否有空
    List<XElement> elementList = new List<XElement>();
    GetElements(xmlDocument.Root.Elements(), "Objects", elementList, "Left");
    List<XAttribute> XAList = GetXattributes(elementList);
 
    foreach (XAttribute item in XAList)
    {
        string XAname = item.Name.LocalName;
        string XAvalue = item.Value;
        if (XAname == "nil" && XAvalue=="true")
        {
            return true;
        }
    }
    return false;
}
 
/// <summary>
/// 获取所有节点的所有属性
/// </summary>
/// <param name="elementList"></param>
/// <returns></returns>
public static List<XAttribute> GetXattributes(List<XElement> elementList)
{
    List<XAttribute> LXA = new List<XAttribute>();
    foreach (XElement item in elementList)
    {
        IEnumerable<XAttribute> dd = item.Attributes();
        var ie = dd.GetEnumerator();                      // 通过GetEnumerator()方法返回IEnumerator迭代器
        while (ie.MoveNext())
        {
            XAttribute XA = ie.Current;
            LXA.Add(XA);
        }
    }
    return LXA;
}
 
 
 
/// <summary>
/// 获取嵌套遍历XML中所有节点
/// </summary>
/// <param name="xElements"></param>
/// <param name="parentNodeName"></param>
/// <param name="elementList">接收</param>
/// <param name="dictionaryValue"></param>
public static void GetElements(IEnumerable<XElement> xElements, string parentNodeName, List<XElement> elementList, string dictionaryValue)
{
    foreach (XElement item in xElements)
    {
        if (item.HasElements)
        {
            GetElements(item.Elements(), parentNodeName + item.Name.ToString(), elementList, dictionaryValue);
        }
        else
        {
            elementList.Add(item);
        }
    }
}

使用:

//读取XML
string inputtext = System.IO.File.ReadAllText("./XMLFile1.xml");
//将xml转换为类再转换为xml(可将必填项设置标识)
string sttt = XmlSerializeHelper.XmlSerialize(XmlSerializeHelper.DeserializeFromXml(inputtext, typeof(qqq)), Encoding.UTF8, new Dictionary<string, string>());
//必填项是否通还有空值
bool BL = IsRequiredItemError(sttt, "标识");
//需要注意的是,数组为空时不会被标注出来,如果大家有什么好的方法的话 欢迎留言


问题:当类赋值后,转换为xml的字符串中 节点多了xmlns属性

原因:当给类中Object类型的属性赋值时, 节点就会自动添加xmlns属性

解决:将Object类型改为string类型即可

xml序列化时类的自定义属性
空值标识:IsNullable

[XmlElement(IsNullable = true)]   当示例转为XML文本时,带有此自定义属性的属性如果为null则会生成  xsi:nil = true 的属性
 
使用方式:[XmlElement(IsNullable = true)]
        public string Str
 
生成结果:<str xsi:nil="true" />
注意:标识一定要写在属性上,不能写在类上,必须写在类内的属性上!!!


指定序列化名称:ElementName

[XmlElement(ElementName = "str")]
public string aaastr
 
序列化结果: <str/>
 注: 不同参数间可以用"," 间隔 如: [XmlElement(ElementName = "str", IsNullable = true)]

取消字段的正反序列化:[XmlIgnore]

使用方法: 在需要忽略序列化的字段上加上[XmlIgnore]即可
        [XmlIgnore]
        public string Str
————————————————
版权声明:本文为CSDN博主「幻世顽灵」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/www89574622/article/details/104679730

posted @ 2022-02-03 23:33  东经115  阅读(1831)  评论(0编辑  收藏  举报