從基礎(chǔ)讀寫到高級技巧詳解C#操作XML的全指南
引言
在 .NET 開發(fā)生態(tài)中,XML(可擴展標(biāo)記語言)雖不如 JSON 那般“時髦”,但在配置文件(如 app.config、.csproj)、數(shù)據(jù)交換、遺留系統(tǒng)集成等場景中依然廣泛存在。C# 提供了多種方式操作 XML,從簡單快捷的 XmlDocument 到現(xiàn)代高效的 XDocument(LINQ to XML),再到底層流式處理的 XmlReader/XmlWriter。
然而,很多開發(fā)者面對這些 API 時常常感到困惑:
- 該用哪種方式?
- 性能如何?
- 如何優(yōu)雅地增刪改查?
- 怎樣避免常見坑點?
本文將帶你系統(tǒng)梳理 C# 操作 XML 的三大主流方式,結(jié)合實戰(zhàn)代碼,一次講透核心用法與最佳實踐。
一、三種主流 XML 操作方式概覽
| 方式 | 類型 | 特點 | 適用場景 |
|---|---|---|---|
| XmlDocument | DOM(文檔對象模型) | 老牌 API,.NET Framework 早期主力 | 小型文檔、需要兼容舊項目 |
| XDocument / XElement | LINQ to XML | 現(xiàn)代、簡潔、支持 LINQ 查詢 | 推薦用于新項目 |
| XmlReader / XmlWriter | 流式(SAX 風(fēng)格) | 內(nèi)存占用低、只讀/只寫、高性能 | 大型 XML 文件處理 |
建議:新項目優(yōu)先使用 XDocument;超大文件(>100MB)考慮 XmlReader。
二、XDocument:現(xiàn)代 C# 操作 XML 的首選
1. 創(chuàng)建 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");
優(yōu)勢:語法簡潔、鏈?zhǔn)秸{(diào)用、天然支持 LINQ,代碼可讀性極高。
三、XmlDocument:經(jīng)典但略顯笨重
雖然 XmlDocument 是 .NET 1.0 時代的產(chǎn)物,但在維護老系統(tǒng)時仍會遇到。
var xmlDoc = new XmlDocument();
xmlDoc.Load("books.xml");
// 查找節(jié)點
XmlNode? bookNode = xmlDoc.SelectSingleNode("http://Book[@Id='1']");
if (bookNode != null)
{
var title = bookNode["Title"]?.InnerText;
Console.WriteLine(title);
}
// 添加節(jié)點
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 冗長,需頻繁類型轉(zhuǎn)換,不支持 LINQ。
四、XmlReader / XmlWriter:處理大型 XML 的利器
當(dāng) XML 文件達到數(shù)百 MB 甚至 GB 級別時,DOM 方式會因加載整個文檔到內(nèi)存而崩潰。此時應(yīng)使用流式處理。
使用 XmlReader 逐節(jié)點讀取
using var reader = XmlReader.Create("huge_file.xml");
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Book")
{
// 只處理 Book 節(jié)點,不加載全文檔
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();
優(yōu)勢:內(nèi)存占用恒定,適合大數(shù)據(jù)量場景。
代價:只能順序讀寫,無法隨機訪問或修改已有內(nèi)容。
五、常見陷阱與最佳實踐
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 時,務(wù)必禁用 DTD 和外部實體:
var settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null
};
using var reader = XmlReader.Create(stream, settings);
六、選型建議總結(jié)
| 需求 | 推薦方案 |
|---|---|
| 新項目、中小型 XML | ? XDocument(LINQ to XML) |
| 維護老系統(tǒng) | ?? XmlDocument(兼容性優(yōu)先) |
| 超大文件(>100MB) | ?? XmlReader / XmlWriter |
| 需要高性能只讀解析 | XmlReader |
| 需要復(fù)雜查詢和動態(tài)構(gòu)建 | XDocument |
結(jié)語
C# 對 XML 的支持歷經(jīng)多年演進,已形成一套完整、靈活且高效的工具鏈。掌握 XDocument 的現(xiàn)代用法,了解 XmlDocument 的歷史背景,熟悉 XmlReader 的性能優(yōu)勢,你就能在任何 XML 場景下游刃有余。
記住:沒有“最好”的 API,只有“最合適”的選擇。根據(jù)你的數(shù)據(jù)規(guī)模、性能要求和維護成本,做出明智決策,才是專業(yè)開發(fā)者的標(biāo)志。
到此這篇關(guān)于從基礎(chǔ)讀寫到高級技巧詳解C#操作XML的全指南的文章就介紹到這了,更多相關(guān)C#操作XML內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c#訪問this關(guān)鍵字和base關(guān)鍵字示例
this關(guān)鍵字引用類的當(dāng)前實例。靜態(tài)成員方法中不能使用this關(guān)鍵字,this關(guān)鍵字只能在實例構(gòu)造函數(shù)、實例方法或?qū)嵗L問器中使用。base關(guān)鍵字用于從派生類中訪問基類的成員。下面學(xué)習(xí)一下這二個關(guān)鍵字的使用方法2014-01-01
C#/VB.NET實現(xiàn)HTML轉(zhuǎn)為XML的示例代碼
可擴展標(biāo)記語言(XML)文件是一種標(biāo)準(zhǔn)的文本文件,它使用特定的標(biāo)記來描述文檔的結(jié)構(gòu)以及其他特性。本文將利用C#實現(xiàn)HTML轉(zhuǎn)為XML,需要的可以參考一下2022-06-06
C#使用WMI實現(xiàn)監(jiān)聽進程的啟動和關(guān)閉
Windows Management Instrumentation(WMI)是用于管理基于 Windows 操作系統(tǒng)的數(shù)據(jù)和操作的基礎(chǔ)結(jié)構(gòu),本文將使用WMI實現(xiàn)監(jiān)聽進程的啟動和關(guān)閉,感興趣的可以了解下2024-01-01
關(guān)于C#生成MongoDB中ObjectId的實現(xiàn)方法
本篇文章小編為大家介紹,關(guān)于C#生成MongoDB中ObjectId的實現(xiàn)方法。需要的朋友參考下2013-04-04

