首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> C# 入門

C# 讀取 XML 完整指南:XmlReader 高效流式解析實作

     編輯:C# 入門

為什麼選 XmlReader?

XmlReader(抽象基類)、XmlTextReader(實作)提供**前向唯讀、流式**存取 XML,記憶體占用極低,適合大型檔案(>100MB)或高效能場景。對比 XmlDocument(DOM、全載入記憶體)與 XDocument(LINQ to XML、較重),XmlReader 是串流處理的首選。

核心 API 速查

成員用途
Read()移至下一節點,回傳 bool;結束時回傳 false。
NodeType當前節點型別:Element、EndElement、Text、XmlDeclaration、Attribute 等。
Name / LocalName節點名稱(含/不含前綴)。
Value文字節點內容、屬性值等。
HasAttributes是否有屬性。
MoveToNextAttribute()在屬性間游標移動。
GetAttribute(name)直接取得指定屬性值。
ReadElementContentAsString()讀取元素文字內容並自動移至 EndElement。
ReadInnerXml() / ReadOuterXml()取得片段 XML 字串。

完整實作:通用 XML 讀取器類別

using System;
using System.Xml;
using System.Collections.Generic;

public sealed class XmlStreamReader : IDisposable {
    private readonly XmlReader _reader;
    private bool _disposed;

    public XmlStreamReader(string filePath, XmlReaderSettings settings = null) {
        _reader = XmlReader.Create(filePath, settings ?? DefaultSettings());
    }

    public XmlStreamReader(Stream stream, XmlReaderSettings settings = null) {
        _reader = XmlReader.Create(stream, settings ?? DefaultSettings());
    }

    private static XmlReaderSettings DefaultSettings() => new() {
        IgnoreWhitespace = true,      // 忽略非意義空白
        IgnoreComments = true,        // 忽略註解
        DtdProcessing = DtdProcessing.Ignore, // 或 Prohibit 防 XXE
        MaxCharactersFromEntities = 1024,     // 防實體擴展攻擊
        Async = false                 // 同步模式;需非同步改 true 配合 ReadAsync
    };

    /// 逐節點迴圈,回呼處理邏輯
    public void Process(Action onNode) {
        while (_reader.Read()) onNode(_reader);
    }

    /// 尋找特定元素並讀取內容
    public IEnumerable ReadElements(string elementName) {
        while (_reader.Read()) {
            if (_reader.NodeType == XmlNodeType.Element && _reader.Name == elementName) {
                yield return _reader.ReadElementContentAsString();
            }
        }
    }

    /// 讀取元素及其屬性為字典
    public IEnumerable> ReadElementsWithAttributes(string elementName) {
        while (_reader.Read()) {
            if (_reader.NodeType == XmlNodeType.Element && _reader.Name == elementName) {
                var dict = new Dictionary();
                if (_reader.HasAttributes) {
                    while (_reader.MoveToNextAttribute()) {
                        dict[_reader.Name] = _reader.Value;
                    }
                    _reader.MoveToElement(); // 重要:移回元素節點
                }
                dict["_text"] = _reader.ReadElementContentAsString();
                yield return dict;
            }
        }
    }

    public void Dispose() {
        if (!_disposed) {
            _reader?.Close();
            _disposed = true;
        }
    }
}

使用範例

// XML 範例:
// 
//   C# in Depth
//   Three Body
// 

using (var reader = new XmlStreamReader("books.xml")) {
    // 1. 簡單列印所有節點
    reader.Process(r => Console.WriteLine($"{r.NodeType}: {r.Name} = {r.Value}"));

    // 2. 只讀取書名
    foreach (var title in reader.ReadElements("title")) {
        Console.WriteLine($"Title: {title}");
    }

    // 3. 讀取 book 元素完整資訊
    foreach (var book in reader.ReadElementsWithAttributes("book")) {
        Console.WriteLine($"ID={book["id"]}, Category={book["category"]}, Title={book["_text"]}");
    }
}

進階主題

  • 非同步讀取:設定 Async=true,使用 await reader.ReadAsync(),配合 ReadElementContentAsStringAsync(),避免阻塞 UI/執行緒池。
  • Schema 驗證:settings.ValidationType = ValidationType.Schema; settings.Schemas.Add(...); settings.ValidationEventHandler += (s,e)=>...;
  • 命名空間處理:使用 reader.NamespaceURI、reader.Prefix,或 reader.GetAttribute("name", "nsUri")。
  • 大檔案分塊處理:搭配 ReadSubtree() 取得子樹獨立 Reader,局部處理後釋放。

常見錯誤與避坑

  1. 忘記 MoveToElement():遍歷屬性後游標停在最後一個屬性,後續 Read() 會異常。
  2. 未處理 DTD/實體:預設會解析 DTD,導致 XXE 攻擊或效能問題,務必設定 DtdProcessing.Ignore/Prohibit。
  3. 混用 Read/ReadElementContentAsXxx:後者會自動推進到 EndElement,不可再手動 Read()。
  4. 編碼不匹配:XML 宣告 encoding 與實際檔案編碼不一致會拋異常,必要時用 StreamReader 指定編碼後傳給 XmlReader.Create。

結語

XmlReader 是 .NET XML 處理的基石,掌握其流式模型、游標語意與安全設定,能編寫高效能、低記憶體、抗攻擊的 XML 解析器。封裝為 XmlStreamReader 類別後,業務代碼更聚焦於資料提取邏輯,提升可讀性與可測試性。

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