在C#桌面与后台服务开发中,操作XML配置或报文是常见任务。XmlDocument是.NET框架提供的基于W3C DOM标准的XML文档对象模型,它将整份XML加载到内存形成节点树,允许程序任意遍历、查询、新增、删除与修改节点,最后写回文件或流。理解它的核心类和常用方法,是处理传统系统对接的基础。

一、XmlDocument核心概念
XmlDocument位于System.Xml命名空间,使用前需添加using引用。它本身代表整个XML文档,内部通过XmlNode作为抽象基类,派生出XmlElement(元素)、XmlAttribute(属性)、XmlText(文本)等具体节点类型。文档必须拥有且仅有唯一根元素,所有业务节点挂在根下。
与后来推出的XDocument(LINQ to XML)不同,XmlDocument强调显式的节点创建与挂载,例如用CreateElement生成元素,用AppendChild建立父子关系。这种方式虽然代码稍长,但在需要精确控制节点顺序、处理XML命名空间或兼容老旧代码时依然可靠。下面是一个最基础的加载示例:
using System;
using System.Xml;
class Demo
{
static void Main()
{
XmlDocument doc = new XmlDocument();
// 从字符串加载XML,注意根节点必须存在
doc.LoadXml("<root><item>测试</item></root>");
XmlElement root = doc.DocumentElement;
Console.WriteLine(root.Name); // 输出 root
}
}
二、读取XML文件的常用方式
实际项目中XML常驻留于磁盘。XmlDocument提供了Load方法,可接受文件路径、Stream或TextReader。若文件包含中文,务必确认文件本身是UTF-8编码且与声明一致,否则会出现乱码或解析异常。以下代码演示从本地文件读取并遍历子节点:
using System;
using System.Xml;
class ReadDemo
{
static void Main()
{
XmlDocument doc = new XmlDocument();
// 加载当前目录下的config.xml
doc.Load("config.xml");
XmlNodeList nodes = doc.SelectNodes("/root/item");
if (nodes != null)
{
foreach (XmlNode node in nodes)
{
Console.WriteLine(node.InnerText);
}
}
}
}
除了直接遍历,XmlDocument支持XPath查询。SelectSingleNode可定位唯一节点,SelectNodes返回集合。XPath中若遇命名空间,需配合XmlNamespaceManager,否则查不到节点。很多初学者在带ns前缀的XML上卡住,就是漏了管理器注册这一步。
读取属性也很简单:通过XmlAttributeCollection或Element.GetAttribute。当节点可能不存在时,先判空再取InnerText,能避免空引用异常。对于深层嵌套,建议封装一个安全取值方法,减少重复判断代码。
三、创建与写入XML文档
生成新XML时,先构造XmlDocument,用AppendChild加入根,再逐步添加子元素与属性。CreateElement的第二个参数可传命名空间URI,处理带前缀的文档。写完用Save方法输出,可保存到路径或写入StringWriter得到字符串。
using System;
using System.Xml;
class WriteDemo
{
static void Main()
{
XmlDocument doc = new XmlDocument();
// 创建XML声明
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(dec);
XmlElement root = doc.CreateElement("root");
doc.AppendChild(root);
XmlElement item = doc.CreateElement("item");
item.SetAttribute("id", "1");
item.InnerText = "第一条数据";
root.AppendChild(item);
doc.Save("output.xml");
}
}
上述代码会生成带声明、根及子项的文件。注意InnerText赋值时,若内容含有<、>、&等符号,XmlDocument会自动转义,无需手动替换,这比字符串拼接安全得多。但如果用InnerXml直接塞片段,则要自己保证片段合法。
需要修改已有节点时,先SelectSingleNode找到目标,改其InnerText或属性,再Save覆盖原文件。由于DOM全量载入,文件很大时会吃内存,此时应考虑XmlReader流式处理。对于普通几兆以内的配置,XmlDocument足够直观好用。
四、特殊字符与命名空间处理
XML规范限定部分字符必须转义。在C#侧,只要走XmlDocument的节点文本赋值,框架会替你完成。但如果你从外部拼好字符串再LoadXml,就要先清理非法字符(如控制符),否则抛异常。下表列出常见转义对应关系:
| 原始字符 | XML实体 |
|---|---|
| < | < |
| > | > |
| & | & |
命名空间方面,假设XML带<ns:root xmlns:ns="http://ipipp.com/schema">,查询时要先建管理器:
using System;
using System.Xml;
class NsDemo
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<ns:root xmlns:ns='http://ipipp.com/schema'><ns:item>值</ns:item></ns:root>");
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("ns", "http://ipipp.com/schema");
XmlNode node = doc.SelectSingleNode("//ns:item", mgr);
Console.WriteLine(node != null ? node.InnerText : "未找到");
}
}
忽略命名空间是XmlDocument查询失败的主因之一。另外,Save默认按声明编码写文件,若想内存中转字符串,用StringWriter并指定Encoding,可避免BOM带来的接口解析问题。
五、XmlDocument与XDocument的选择
新项目若目标框架是.NET Core或现代.NET,官方更推荐XDocument,语法更简洁且 LINQ 友好。但维护旧工控软件、Web Service早期契约,或需严格按节点顺序生成报文时,XmlDocument仍是稳妥方案。二者可共存,不必强行迁移。
总结来看,XmlDocument以树形操作平衡了灵活与可控,掌握Load、Save、XPath与命名空间四件事,就能覆盖绝大多数C# XML读写场景。写代码时优先让框架处理转义,少用字符串硬拼,可显著降低线上故障率。
XmlDocumentC#_XMLXML操作修改时间:2026-08-05 18:21:32