C# XML 序列化与反序列化

简介与实现

.NET提供了很不错的XML序列化/反序列化器
所在命名空间:System.Xml.Serialization

  • 封装实现代码
using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace Unified.Services.Core
{
    public class XmlSerializerHelper
    {
        /// <summary>  
        /// 将XML序列化为实体
        /// </summary>  
        /// <typeparam name="T"></typeparam>  
        /// <param name="xmlObj"></param>  
        /// <returns></returns>  
        public static T DeserializeXML<T>(string xmlObj)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T),new XmlRootAttribute("response"));
            using (StringReader reader = new StringReader(xmlObj))
            {
                return (T)serializer.Deserialize(reader);
            }
        }

        /// <summary>
        /// 将对象序列化为xml
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string SerializeXml(object data)
        {
            using (StringWriter sw = new StringWriter())
            {
                XmlSerializer xz = new XmlSerializer(data.GetType());
                xz.Serialize(sw, data);

                XElement xmlDocumentWithoutNs = RemoveAllNamespaces(XElement.Parse(sw.ToString()));

                return xmlDocumentWithoutNs.ToString();
            }
        }

        /// <summary>
        /// 删除命名空间
        /// </summary>
        /// <param name="xmlDocument"></param>
        /// <returns></returns>
        private static XElement RemoveAllNamespaces(XElement xmlDocument)
        {
            return new XElement(xmlDocument.Name.LocalName,
                xmlDocument.Attributes()
                    .Where(a => !a.IsNamespaceDeclaration)
                    .Select(a => new XAttribute(a.Name.LocalName, a.Value)),
                xmlDocument.Nodes().Select(n =>
                    n is XElement child ? RemoveAllNamespaces(child) : n));
        }
    }
}

注意事项

xml 字符串验证

/// <summary>
/// Xml字符串格式验证
/// </summary>
/// <param name="xmlString">Xml字符串</param>
/// <returns></returns>
public static bool IsValidXml(string xmlString)
{
    try
    {
        // 创建XmlDocument对象,加载xml字符串
        new XmlDocument().LoadXml(xmlString);
        // 如果没有异常,则说明xml字符串是有效的
        return true;
    }
    catch (XmlException)
    {
        // 如果有异常,则说明xml字符串是无效的
        return false;
    }
}

实体序列化为 xml

序列化集合的时候不要“再包一层”

[XmlRoot("department")]
public class Department {
    public string DeptName { get; set; }
    
	[XmlElement("Employee")]
    public List<Employee> Details { get; set; }
}

xml序列化与json序列化不一样,顶级标签名是当前实体的 Class Name 所以需要进行特性标注[XmlRoot("elementName")],标注之后当前类的 Class Name 就成了序列化之后xml的顶级标签名。

List 集合类型序列化也同样需要进行标注,如上。

双标签序列化

空元素可能输出为 <Name />,与 <Name></Name> 在 XML 语义上等价。null 属性通常被省略;[XmlElement(IsNullable = true)] 可输出 xsi:nil。如对接协议强制要求双标签,应单独控制 XML 写出方式,本辅助类不保证这种格式。

删除命名空间

xml 序列化之后默认会有类似下面这种,带有 namespace 的内容

<department xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- blah blah blah -->
</department>

实现代码中的 RemoveAllNamespaces() 方法就是用来删除 namespace 的

xml 序列化为实体

xml 序列化为实体需要注意的是顶级标签 XmlRootAttribute("elementName") 这里默认是添加了指定顶级标签名的

示例约定

反序列化方法把根节点固定为 response,仅适用于对应协议;使用 department 等模型时,应改为匹配的根名称,或使用 new XmlSerializer(typeof(T)) 读取模型上的 [XmlRoot]。Employee 为业务模型,需要自行定义,并引入 System.Collections.Generic。[XmlElement("Employee")] 将集合项直接输出到父节点;需要集合外层标签时使用 XmlArray 与 XmlArrayItem。

删除命名空间只适用于明确不使用命名空间的协议:同名、不同命名空间的属性可能冲突,xsi:nil 等语义也可能丢失,常规序列化建议保留命名空间。本示例的 XML 验证只检查语法,不验证 XSD 或业务字段。

参考:使用特性控制 XML 序列化。

posted @ 2026-10-05 18:38  JacePan  阅读(6)  评论(0)    收藏  举报