XML序列化是指把程序运行时的对象状态,按照可扩展标记语言的规范转换为字符串或文件的过程。借助序列化,开发者无需手动拼接尖括号与属性,就能把复杂对象图稳定地输出为结构化的XML文本,便于跨系统交换或本地持久化。

一、XML序列化的基本概念
在面向对象语言中,对象通常只存在于内存堆中,无法直接通过网络发送或落盘保存。XML序列化通过反射读取对象的公共成员,将类名映射为根节点,把属性或字段映射为子节点或属性,最终生成符合XML标准的文档。这种方式比手工写字符串更安全,因为序列化器会自动处理特殊字符与编码。
需要注意的是,不同语言对可序列化类型有约束。例如在.NET中,待序列化的类一般要提供无参构造函数,且属性应为public并同时具备get和set;私有字段默认不会被输出,除非使用特定特性标记。理解这些底层规则,才能避免转换时出现对象丢字段的情况。
1.1 序列化与反序列化的关系
序列化关注对象到XML的正向转换,反序列化则是从XML文本重建对象。两者依赖同一份结构约定,如果节点命名或类型不匹配,反序列化就会失败。因此在设计DTO(数据传输对象)时,应当优先考虑双方系统都能识别的命名风格。
很多团队会用特性来控制节点名称,比如把后台模型的UserName输出为user_name,从而兼容外部老旧接口。这种映射能力正是XML序列化相比单纯ToString的优势所在。
二、如何将对象转换为XML字符串
以C#为例,最常用的是System.Xml.Serialization命名空间下的XmlSerializer。下面演示一个最简转换:定义一个普通类,创建实例后通过StringWriter接收输出。
using System;
using System.IO;
using System.Xml.Serialization;
public class Book
{
public string Title { get; set; }
public decimal Price { get; set; }
}
class Program
{
static void Main()
{
Book book = new Book { Title = "C#入门", Price = 59.9m };
XmlSerializer serializer = new XmlSerializer(typeof(Book));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, book);
string xmlString = writer.ToString();
Console.WriteLine(xmlString);
}
}
}
上述代码运行后会得到包含Book根节点、内部含Title与Price子节点的XML字符串。StringWriter默认使用系统编码,若需指定UTF-8不带BOM,可传入特定StringWriter实现。
如果希望去掉默认命名空间,可以传入XmlSerializerNamespaces并添加空前缀,这样生成的XML更干净,也更容易被第三方解析器接受。对于含有集合属性的对象,序列化器会自动展开为多个重复节点,无需额外编码。
2.1 使用特性定制输出
通过XmlElement、XmlAttribute等特性,可以精确控制每个成员在XML中的形态。例如把Price作为节点属性而非子元素,能减少嵌套层级。
using System.Xml.Serialization;
public class Book
{
[XmlElement("book-name")]
public string Title { get; set; }
[XmlAttribute("price")]
public decimal Price { get; set; }
}
加上这些特性后,输出的XML会变成<Book price="59.9"><book-name>C#入门</book-name></Book>。这种细粒度控制,在对接严格格式的报文时非常实用。
此外,若对象图中存在继承关系,还需用XmlInclude告知序列化器可能的具体子类,否则运行时会产生未知类型异常。提前在基类上声明,可保证多态对象也能顺利转为字符串。
三、常见问题与规避方式
实践中,开发者常遇到“私有字段未输出”或“循环引用导致堆栈溢出”的问题。前者可通过改为公开属性解决,后者应避免在对象间互相反向引用,或改用支持忽略循环引用的第三方库。
| 问题现象 | 产生原因 | 应对方案 |
|---|---|---|
| 生成的XML缺少某些字段 | 字段为private或未设setter | 改为public属性并配get/set |
| 反序列化时报未知节点 | 两端类结构不一致 | 统一特性命名或忽略多余节点 |
| 特殊字符破坏格式 | 手工拼接未转义 | 使用序列化器自动转义 |
从表中可以看出,绝大多数异常都源于对序列化规则不熟悉。采用框架自带的序列化而非手写拼接,本身就能规避最后一类字符转义风险。
当对象包含日期时间时,建议明确指定格式,因为不同地区序列化出的字符串可能不同,导致对方解析失败。利用XmlSerializer配合自定义日期格式类,或在特性中约束,是稳妥做法。
四、小结
XML序列化本质是用统一规则把对象公开状态映射为XML文本,它降低了跨平台数据交换的编码成本。掌握基础API、特性标注与命名空间控制,就能把任意合规对象快速转为XML字符串,并保持良好的可读性与稳定性。
在微服务或老旧系统对接场景中,这种转换方式依旧具有生命力。比起JSON,XML在报文校验与节点属性表达上更严谨,合理使用序列化工具,可让对象转换工作事半功倍。