XmlDocument适合中小XML文件,语法直观但内存占用高;XmlReader适合超大文件,流式解析内存恒定;XDocument语法简洁、内存更省,支持LINQ查询;解析失败多因XML不规范、编码不一致或隐藏字符。
XmlDocument 加载并遍历节点最直接适合中小 XML 文件(几百 KB 以内),语法直观,支持 XPath 查询。注意它会把整个文档加载进内存,大文件容易 OOM。
Load() 接收文件路径、Stream 或 TextReader,推荐用 FileStream 避免编码问题DocumentElement,子节点用 ChildNodes 或 SelectNodes("xpath")
node.Attributes["id"]?.Val
ue,否则可能抛 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.Element 和 XmlNodeType.Text 时取值var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit };
using var reader = XmlReader.Create("big.xml", 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 是否合法、编码是否一致、有没有隐藏控制字符 —— 这些往往比解析逻辑更耗时间。