c# 如何解析xml文件

XmlDocument适合中小XML文件,语法直观但内存占用高;XmlReader适合超大文件,流式解析内存恒定;XDocument语法简洁、内存更省,支持LINQ查询;解析失败多因XML不规范、编码不一致或隐藏字符。

XmlDocument 加载并遍历节点最直接

适合中小 XML 文件(几百 KB 以内),语法直观,支持 XPath 查询。注意它会把整个文档加载进内存,大文件容易 OOM。

  • Load() 接收文件路径、StreamTextReader,推荐用 FileStream 避免编码问题
  • 根节点是 DocumentElement,子节点用 ChildNodesSelectNodes("xpath")
  • 取属性值别忘了判空:node.Attributes["id"]?.Value,否则可能抛 NullReferenceException
var doc = new XmlDocument();
doc.Load("config.xml");
var items = doc.SelectNodes("/root/item");
foreach (XmlNode node in items) {
    string name = node["name"]?.InnerText ?? "";
    string id = node.Attributes["id"]?.Value ?? "";
}

大文件必须用 XmlReader 流式解析

内存占用恒定,但只能单向读取,不支持随机访问或修改。适用于日志、导出数据等超大 XML(GB 级)。

  • XmlReader.Create() 构造,传入 XmlReaderSettings 关闭 DTD 解析(防 XXE)
  • 核心逻辑靠 Read() + NodeType 判断:只在 XmlNodeType.ElementXmlNodeType.Text 时取值
  • 遇到嵌套结构要自己维护栈或状态机,不能依赖父节点导航
var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit };
using var reader = XmlReader.Create("big.x

ml", settings); while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element && reader.Name == "record") { reader.Read(); // 跳到内容 if (reader.NodeType == XmlNodeType.Text) { Console.WriteLine(reader.Value); } } }

XDocument(LINQ to XML)写起来最简洁

语法糖多,支持 LINQ 查询,适合配置类、结构清晰的小 XML。底层仍是基于 XmlReader,但比 XmlDocument 内存更省。

  • XDocument.Load() XElement.Load() 都可直接读文件
  • 属性用 element.Attribute("name")?.Value,元素内容用 element.Element("child")?.Value
  • Descendants() 替代 XPath 的 //item,但不支持完整 XPath 语法
var doc = XDocument.Load("data.xml");
var items = doc.Root?.Descendants("item")
    .Select(x => new {
        Id = x.Attribute("id")?.Value,
        Name = x.Element("name")?.Value
    }).ToList();

解析失败常见原因和绕过方法

不是代码写错,而是 XML 本身不规范。.NET 默认严格校验,稍有偏差就报错。

  • System.Xml.XmlException: 根级别上的数据无效 → 文件开头有 BOM 或空白字符,用 StreamReader 指定编码再传给 XmlReader
  • 无法找到文档类型定义 → 关闭 DTD:settings.DtdProcessing = DtdProcessing.Prohibit
  • 中文乱码 → 不要直接用 File.ReadAllText() 读完再 Load,XML 声明里的编码(如 encoding="gb2312")必须被尊重

真正难的不是选哪个 API,而是确认 XML 是否合法、编码是否一致、有没有隐藏控制字符 —— 这些往往比解析逻辑更耗时间。