xdocument.load()可简洁加载xml并支持linq查询,需注意空引用、命名空间及descendants()性能;修改时避免边遍历边删,大数据量应选xmlreader。

怎么用 XDocument 读取 XML 文件并查节点
直接用 XDocument.Load() 加载文件,比 XmlDocument 更简洁、更符合 LINQ 风格。它返回一个可查询的树结构,所有节点都是 XElement 类型。
常见错误是路径写错或忽略命名空间——比如用 doc.Root.Element("Item") 却没检查 Root 是否为 null,或 XML 带了默认命名空间却没声明前缀。
XDocument doc = XDocument.Load("config.xml");- 查子节点推荐用
Descendants()而非嵌套Element(),避免空引用:例如doc.Descendants("user").FirstOrDefault()?.Attribute("id")?.Value - 若 XML 有命名空间(如
xmlns="http://example.com/ns"),必须用XNamespace构造前缀:XNamespace ns = "http://example.com/ns"; var user = doc.Root?.Element(ns + "user");
怎么用 LINQ 查询 XML 并过滤/投影数据
XDocument 和 System.Xml.Linq 天然支持 LINQ to Objects,但注意:它不是“LINQ to XML”引擎,只是把 XML 节点当普通集合来查,所以不能像 SQL 那样跨层级自动 join,得靠 Descendants() 或 Elements() 显式导航。
性能上,Descendants() 是全树遍历,大数据量时慎用;Elements() 只查直系子节点,更快也更安全。
- 查所有带特定属性值的节点:
doc.Descendants("book").Where(e => e.Attribute("category")?.Value == "fiction") - 投影成匿名对象:
select new { Title = e.Element("title")?.Value, Price = (decimal?)e.Element("price") }(注意 null 合理处理) - 别在查询里反复调用
e.Element("xxx"),先存变量避免重复解析
怎么修改和保存 XML(增删改)
XElement 是可变的,所有操作都直接改原树,没有“只读副本”概念。这意味着:一旦你拿到某个 XElement 引用,对它的修改会立刻反映在 XDocument 中。
容易踩的坑是边遍历边删除——用 Remove() 会导致枚举器失效,报 InvalidOperationException。正确做法是先收集要删的节点,再统一删。
- 添加子元素:
root.Add(new XElement("item", new XAttribute("id", "100"), "new content")); - 修改属性:
elem.SetAttributeValue("status", "active");(不存在则新增,存在则覆盖) - 删除节点:
doc.Root?.Elements("temp").ToList().ForEach(e => e.Remove());(关键:先ToList()) - 保存:
doc.Save("output.xml");,注意它会按当前缩进格式写入,如需控制缩进,设doc.Save(writer)配合XmlWriterSettings
什么时候不该用 XDocument?
它适合中等大小、内存能容纳的 XML(一般 ≤10MB)。如果 XML 很大(如日志归档、GB 级配置),或者只需要顺序读一小段,XDocument 会一次性加载全部到内存,可能 OOM。
此时应换用 XmlReader 流式解析,或者用 XNode.ReadFrom() 分段构造节点。另外,如果项目还依赖老版本 .NET Framework 2.0(无 LINQ),也得退回 XmlDocument。
还有一个隐性限制:XDocument 不支持 DTD 解析和实体展开,遇到含 或自定义实体的 XML 会跳过或报错。










