从基础读写到高级技巧详解C#操作XML的全指南
引言
在 .NET 开发生态中,XML(可扩展标记语言)虽不如 JSON 那般“时髦”,但在配置文件(如 app.config、.csproj)、数据交换、遗留系统集成等场景中依然广泛存在。C# 提供了多种方式操作 XML,从简单快捷的 XmlDocument 到现代高效的 XDocument(LINQ to XML),再到底层流式处理的 XmlReader/XmlWriter。
然而,很多开发者面对这些 API 时常常感到困惑:
- 该用哪种方式?
- 性能如何?
- 如何优雅地增删改查?
- 怎样避免常见坑点?
本文将带你系统梳理 C# 操作 XML 的三大主流方式,结合实战代码,一次讲透核心用法与最佳实践。
一、三种主流 XML 操作方式概览
| 方式 | 类型 | 特点 | 适用场景 |
|---|---|---|---|
| XmlDocument | DOM(文档对象模型) | 老牌 API,.NET Framework 早期主力 | 小型文档、需要兼容旧项目 |
| XDocument / XElement | LINQ to XML | 现代、简洁、支持 LINQ 查询 | 推荐用于新项目 |
| XmlReader / XmlWriter | 流式(SAX 风格) | 内存占用低、只读/只写、高性能 | 大型 XML 文件处理 |
建议:新项目优先使用 XDocument;超大文件(>100MB)考虑 XmlReader。
二、XDocument:现代 C# 操作 XML 的首选
1. 创建 XML
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Books",
new XElement("Book",
new XAttribute("Id", "1"),
new XElement("Title", "C# in Depth"),
new XElement("Author", "Jon Skeet")
)
)
);
doc.Save("books.xml");
2. 读取与查询(LINQ 强大之处)
var doc = XDocument.Load("books.xml");
// 查询所有书名
var titles = doc.Descendants("Title")
.Select(t => t.Value)
.ToList();
// 查询 Id=1 的书
var book = doc.Descendants("Book")
.FirstOrDefault(b => b.Attribute("Id")?.Value == "1");
Console.WriteLine(book?.Element("Title")?.Value);
3. 修改与删除
// 添加新书
doc.Root?.Add(
new XElement("Book",
new XAttribute("Id", "2"),
new XElement("Title", "Effective C#"),
new XElement("Author", "Bill Wagner")
)
);
// 删除某本书
var bookToDelete = doc.Descendants("Book")
.FirstOrDefault(b => b.Attribute("Id")?.Value == "1");
bookToDelete?.Remove();
doc.Save("books.xml");
优势:语法简洁、链式调用、天然支持 LINQ,代码可读性极高。
三、XmlDocument:经典但略显笨重
虽然 XmlDocument 是 .NET 1.0 时代的产物,但在维护老系统时仍会遇到。
var xmlDoc = new XmlDocument();
xmlDoc.Load("books.xml");
// 查找节点
XmlNode? bookNode = xmlDoc.SelectSingleNode("//Book[@Id='1']");
if (bookNode != null)
{
var title = bookNode["Title"]?.InnerText;
Console.WriteLine(title);
}
// 添加节点
XmlElement newBook = xmlDoc.CreateElement("Book");
newBook.SetAttribute("Id", "3");
var titleElem = xmlDoc.CreateElement("Title");
titleElem.InnerText = "Pro C#";
newBook.AppendChild(titleElem);
xmlDoc.DocumentElement?.AppendChild(newBook);
xmlDoc.Save("books.xml");
缺点:API 冗长,需频繁类型转换,不支持 LINQ。
四、XmlReader / XmlWriter:处理大型 XML 的利器
当 XML 文件达到数百 MB 甚至 GB 级别时,DOM 方式会因加载整个文档到内存而崩溃。此时应使用流式处理。
使用 XmlReader 逐节点读取
using var reader = XmlReader.Create("huge_file.xml");
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Book")
{
// 只处理 Book 节点,不加载全文档
var id = reader.GetAttribute("Id");
// 进一步解析子元素(可配合 ReadSubtree)
}
}
使用 XmlWriter 高效写入
using var writer = XmlWriter.Create("output.xml", new XmlWriterSettings { Indent = true });
writer.WriteStartDocument();
writer.WriteStartElement("Books");
writer.WriteStartElement("Book");
writer.WriteAttributeString("Id", "1");
writer.WriteElementString("Title", "Clean Code");
writer.WriteEndElement(); // Book
writer.WriteEndElement(); // Books
writer.WriteEndDocument();
优势:内存占用恒定,适合大数据量场景。
代价:只能顺序读写,无法随机访问或修改已有内容。
五、常见陷阱与最佳实践
1. 忘记处理命名空间(Namespace)
XML 带命名空间时,直接用 Descendants("Name") 会查不到!
<book xmlns="http://example.com/books"> <title>C# Guide</title> </book>
正确做法:
XNamespace ns = "http://example.com/books"; var title = doc.Descendants(ns + "title").First().Value;
2. 字符编码问题
保存 XML 时指定编码:
doc.Save(new StreamWriter("file.xml", false, Encoding.UTF8));
// 或使用 XDocument + SaveOptions
3. 安全性:警惕 XXE 攻击
在解析不受信任的 XML 时,务必禁用 DTD 和外部实体:
var settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null
};
using var reader = XmlReader.Create(stream, settings);
六、选型建议总结
| 需求 | 推荐方案 |
|---|---|
| 新项目、中小型 XML | ✅ XDocument(LINQ to XML) |
| 维护老系统 | ⚠️ XmlDocument(兼容性优先) |
| 超大文件(>100MB) | 🔥 XmlReader / XmlWriter |
| 需要高性能只读解析 | XmlReader |
| 需要复杂查询和动态构建 | XDocument |
结语
C# 对 XML 的支持历经多年演进,已形成一套完整、灵活且高效的工具链。掌握 XDocument 的现代用法,了解 XmlDocument 的历史背景,熟悉 XmlReader 的性能优势,你就能在任何 XML 场景下游刃有余。
记住:没有“最好”的 API,只有“最合适”的选择。根据你的数据规模、性能要求和维护成本,做出明智决策,才是专业开发者的标志。
到此这篇关于从基础读写到高级技巧详解C#操作XML的全指南的文章就介绍到这了,更多相关C#操作XML内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
C# AutoResetEvent和ManualResetEvent的实现示例
本文主要介绍了C# AutoResetEvent和ManualResetEvent的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2025-11-11


最新评论