首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# XML 操作完整指南:XmlDocument 增刪改查、XPath、LINQ to XML 現代化遷移

     編輯:關於C語言

前言

XML 在 .NET 生態系統中扮演重要角色:設定檔 (app.config/web.config)、資料交換、文件格式 (Office Open XML)、WS-* 訊息。本文以經典 XmlDocument (DOM) 為基礎,示範完整 CRUD 操作,並對比 XPath、LINQ to XML (XDocument) 現代化寫法,幫助你選擇最適合的 API。

一、範例資料:bookstore.xml

<?xml version="1.0" encoding="utf-8"?>
<bookstore>
  <book genre="fantasy" ISBN="2-3631-4">
    <title>Oberon's Legacy</title>
    <author>Corets, Eva</author>
    <price>5.95</price>
  </book>
</bookstore>

二、XmlDocument (DOM) 完整操作

1. 載入與導航


var doc = new XmlDocument();
doc.Load("bookstore.xml"); // 或 LoadXml(string), Load(Stream)

// 根節點
XmlNode root = doc.DocumentElement; // 或 SelectSingleNode("bookstore")

// 取得所有 book 節點
XmlNodeList books = root.SelectNodes("book"); // XPath
// 或 root.ChildNodes (含文字節點、註解)

2. 新增節點 (Create → Append)


// 建立元素與屬性
XmlElement newBook = doc.CreateElement("book");
newBook.SetAttribute("genre", "scifi");
newBook.SetAttribute("ISBN", "978-3-16-148410-0");

// 子元素
XmlElement title = doc.CreateElement("title");
title.InnerText = "Dune";
newBook.AppendChild(title);

XmlElement author = doc.CreateElement("author");
author.InnerText = "Frank Herbert";
newBook.AppendChild(author);

XmlElement price = doc.CreateElement("price");
price.InnerText = "12.99";
newBook.AppendChild(price);

// 加入根節點
root.AppendChild(newBook);
doc.Save("bookstore.xml");

3. 修改節點


// 方式 A: XPath 定位 + 直接修改
XmlNode book = root.SelectSingleNode("book[@genre='fantasy']");
if (book != null)
{
    XmlElement elem = (XmlElement)book;
    elem.SetAttribute("genre", "updated-fantasy"); // 修改屬性
    
    XmlNode authorNode = elem.SelectSingleNode("author");
    if (authorNode != null) authorNode.InnerText = "New Author"; // 修改文字
}

// 方式 B: 遍歷 ChildNodes
foreach (XmlNode node in root.ChildNodes)
{
    if (node is XmlElement el && el.GetAttribute("genre") == "fantasy")
    {
        el.SetAttribute("genre", "updated-fantasy");
        break;
    }
}
doc.Save("bookstore.xml");

4. 刪除節點與屬性


// 刪除屬性
XmlNode book = root.SelectSingleNode("book[@genre='fantasy']");
((XmlElement)book).RemoveAttribute("genre");

// 刪除整個節點 (含子樹)
XmlNode bookToRemove = root.SelectSingleNode("book[@genre='updated-fantasy']");
if (bookToRemove != null) root.RemoveChild(bookToRemove);

// 刪除節點內容但保留元素
bookToRemove.RemoveAll(); // 變成 
doc.Save("bookstore.xml");

5. 讀取與顯示


foreach (XmlNode book in root.SelectNodes("book"))
{
    XmlElement el = (XmlElement)book;
    Console.WriteLine($"Genre: {el.GetAttribute("genre")}, ISBN: {el.GetAttribute("ISBN")}");
    
    foreach (XmlNode child in el.ChildNodes)
    {
        if (child.NodeType == XmlNodeType.Element)
            Console.WriteLine($"  {child.Name}: {child.InnerText}");
    }
}

三、XPath 查詢速查表

需求XPath方法
所有 book//book 或 /bookstore/bookSelectNodes
genre="fantasy" 的 book//book[@genre='fantasy']SelectSingleNode
第 2 本 book//book[2]
所有 title 文字//title/text()SelectNodes 回傳 XmlNodeList
包含 "Legacy" 的 title//title[contains(text(),'Legacy')]
price > 10 的 book//book[price > 10]

注意:XmlDocument 的 XPath 支援 XPath 1.0,不支援 2.0/3.0 功能 (如 matches())。

四、LINQ to XML (XDocument) 現代化寫法 (.NET 3.5+)

優點:函數式建構、Lambda 查詢、命名空間處理簡單、可序列化為字串/Stream、效能優於 DOM。

1. 載入與查詢


XDocument doc = XDocument.Load("bookstore.xml");

// 所有 book
var books = doc.Descendants("book");

// 篩選 genre
var fantasyBooks = doc.Descendants("book")
    .Where(b => (string)b.Attribute("genre") == "fantasy");

// 投影匿名型別
var list = doc.Descendants("book")
    .Select(b => new 
    {
        Genre = (string)b.Attribute("genre"),
        ISBN = (string)b.Attribute("ISBN"),
        Title = (string)b.Element("title"),
        Author = (string)b.Element("author"),
        Price = (decimal)b.Element("price")
    })
    .ToList();

2. 建構與新增 (函數式建構)


XElement newBook = new XElement("book",
    new XAttribute("genre", "mystery"),
    new XAttribute("ISBN", "978-0-307-47427-8"),
    new XElement("title", "The Girl with the Dragon Tattoo"),
    new XElement("author", "Stieg Larsson"),
    new XElement("price", 9.99)
);

doc.Root.Add(newBook);
doc.Save("bookstore.xml");

3. 修改


var book = doc.Descendants("book")
    .FirstOrDefault(b => (string)b.Attribute("genre") == "fantasy");
if (book != null)
{
    book.SetAttributeValue("genre", "updated-fantasy");
    book.Element("author").SetValue("New Author");
}
doc.Save("bookstore.xml");

4. 刪除


// 刪除屬性
book.Attribute("genre").Remove();

// 刪除整個元素
book.Remove(); // 含子樹

// 刪除子內容
book.Elements().Remove(); // 保留 book 元素與屬性
doc.Save("bookstore.xml");

五、命名空間處理對比


// XmlDocument: 需 XmlNamespaceManager
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("ns", "https://example.com/ns");
var nodes = doc.SelectNodes("//ns:book", nsmgr);

// LINQ to XML: XNamespace 隱性轉換
XNamespace ns = "https://example.com/ns";
var books = doc.Descendants(ns + "book"); // 簡潔!

六、效能與記憶體考量

API模型記憶體適合場景
XmlDocumentDOM (樹狀完整載入)高 (整份文件在記憶體)小型文件、頻繁隨機存取、需 XPath 1.0
XDocumentDOM (函數式)高中小型文件、LINQ 查詢、建構輸出
XmlReader前向唯讀流極低 (逐節點)大型 XML (GB 級)、單向讀取、高效能
XmlWriter前向寫入流極低大量產生 XML、串流輸出

七、序列化替代方案

若資料模型為類別,優先考慮:

  • System.Text.Json (內建、高效能、UTF-8)
  • XmlSerializer (屬性控制 XML 形狀、舊系統相容)
  • DataContractSerializer (WCF 相容、序列化圖形)

手工 XML 操作僅用於:無結構化文件處理、舊版相容、特定 XML 方言 (XSLT、SVG、XAML)。

八、總結:選擇指南

  1. 新專案、中小型 XML → XDocument (LINQ to XML):語法簡潔、型別安全、易維護。
  2. 舊專案維護、需 XPath 1.0 複雜查詢 → XmlDocument。
  3. 大型 XML (超過 50MB)、單向讀取/寫入 → XmlReader/XmlWriter。
  4. 物件圖形序列化 → System.Text.Json / XmlSerializer。
  5. 命名空間密集 → XDocument 明顯優勢。

結語

從 XmlDocument 到 XDocument,再到 XmlReader/JsonSerializer,.NET 的 XML 生態已演進為完整工具箱。理解各 API 的記憶體模型、查詢能力、建構風格,才能在效能、可維護性、相容性三角中做出正確選擇。建議新專案預設採用 XDocument + System.Text.Json 雙軌並行,僅在必要時落回底層流式 API。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved