xdocument加载后找不到节点主因是命名空间干扰或默认忽略空白节点;elements()仅返回元素节点,需用localname绕前缀,取值推荐(int?)elem.attribute("id")防空异常。

新项目直接用 XDocument,除非你正在对接只认 XmlNode 的老系统或 COM 组件。
为什么 XDocument 加载 XML 后找不到节点?
常见现象是调用 doc.Root?.Elements("item") 返回空集合,但 XML 明明有 <item></item>。根本原因通常是命名空间干扰或空白节点处理逻辑不同。
-
XDocument默认忽略空白文本节点(换行、缩进),Elements()只返回元素节点;而XmlDocument的ChildNodes会混入XmlText类型的空白节点,容易误判 - 带前缀的命名空间(如
soap:Envelope)不用手动注册——XDocument通过Name.LocalName或Descendants().Where(x => x.Name.LocalName == "param")就能绕过前缀直接匹配 - 若需保留原始空白(比如配置模板中换行有意义),加载时必须显式传参:
XDocument.Load(stream, LoadOptions.PreserveWhitespace)
如何安全地取属性值和子元素值?
避免 NullReferenceException 是日常高频痛点。XDocument 提供了可空类型转换和链式安全访问,比 XmlDocument 的 GetAttribute("id") + 判空 + int.Parse 组合更稳。
- 取属性值并转为
int?:(int?)elem.Attribute("id"),空属性或非数字直接得null,不抛异常 - 取子元素文本并转为
double:(double?)elem.Element("price")?.Value,中间任一环节为null都不会崩 - 不要写
elem.Element("user").Element("name").Value—— 改用elem.Descendants("name").FirstOrDefault()?.Value,结构变动时更耐扛
大文件解析内存爆掉怎么办?
XDocument.Load() 和 XmlDocument.Load() 都是全量加载到内存,对几十 MB 以上的 XML 没区别。真要处理大文件,得放弃“全树加载”思路,改用流式提取。
- 用
XmlReader定位到目标节点,再用XElement.ReadFrom(reader)单独加载该节点——既享受XElement的 API 便利,又避开内存压力 - 示例中提取所有
<workstation></workstation>节点时,reader.Read()是逐行扫描,XElement.ReadFrom()只解析当前匹配的完整元素,其余跳过 - 别指望
XDocument.LoadAsync()解决大文件问题——它只是异步 IO,加载后仍占整块内存
命名空间不是“加个 manager 就完事”,它是整个查询逻辑的起点;类型自动转换看着省事,但 (int?) 和 (int) 行为差异极大,漏掉问号就可能在线上突然炸开。











