SelectSingleNode 返回 null 的主因是根节点名错误、命名空间未注册或换行生成干扰的 #text 节点;需确认根名、注册 XmlNamespaceManager、避免 // 通配符滥用。

SelectSingleNode 返回 null?别急着改逻辑,先看根节点名对不对、有没有命名空间、换行是不是生成了干扰的 #text 节点——90% 的“查不到”问题出在这三处。
XmlDocument.SelectSingleNode 总是 null,怎么快速定位原因
不是 API 失效,而是查询条件和实际 XML 结构不匹配。最常见两个硬伤:
-
XPath路径写错:比如文档根是<catalog>,你却写/books/book,必然返回null - XML 含默认命名空间(
xmlns="http://ns.example.com"),但没注册XmlNamespaceManager,直接用//book就失效
实操建议:
- 加载后立刻打印
doc.DocumentElement.OuterXml,确认真实根名、大小写、子节点结构(注意缩进换行会生成#text节点,可能让FirstChild不是你想的<book>) - 含命名空间时必须配
XmlNamespaceManager:var nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("ns", "http://ns.example.com"); doc.SelectSingleNode("/ns:catalog/ns:book", nsmgr); - 少用
//book,优先写绝对路径如/catalog/book[1]/title,性能好、意图明确、不易误匹配
XDocument 为什么比 XmlDocument 更推荐用于新项目
不是“更高级”,而是更贴合现代 C# 的表达习惯和工程需求:
-
XDocument原生支持 LINQ 查询,doc.Descendants("Book").Where(b => b.Attribute("Id")?.Value == "1")比SelectSingleNode+ 类型转换清爽得多 - 创建 XML 更简洁:
new XElement("Book", new XAttribute("Id", "1"), new XElement("Title", "C# in Depth")),不用反复调CreateElement/AppendChild - 没有隐式命名空间处理陷阱:
XDocument.Load默认忽略默认命名空间,除非你显式用XNamespace,反而降低出错概率 - 但注意:
XDocument是全内存加载,超大文件(>100MB)仍得切回XmlReader流式处理
修改节点后 Save() 没生效,常见权限与流陷阱
不是代码没执行,而是文件根本没被写入成功:
- 别手动传
FileStream给Save():用doc.Save("path.xml")即可;若自己File.OpenWrite()再传进去,容易忘记Dispose或写入位置错乱 - 检查目标路径是否可写:Windows 下避开
C:\Program Files\,.NET Core 运行时默认无管理员权限;Mac/Linux 注意目录chmod - 文件是否被其他进程锁定?VS、记事本、甚至另一个调试中的程序都可能独占打开它,导致
UnauthorizedAccessException - 改值用
node.Value = "new"或node.SetValue("new"),别用node.ReplaceAll(...)——后者会删掉所有子节点,把<name><first>A</first><last>B</last></name>直接干成纯文本
XmlSerializer 反序列化后字段全为 null,八成是类定义没对齐
报错 InvalidOperationException: “无法将字符串 '123' 转换为 int” 或字段始终 null,几乎可以确定不是数据问题,而是契约失配:
- 属性必须有 public get/set:只读自动属性
public string Name { get; }会导致反序列化失败,得改成public string Name { get; set; } - 类名/属性名必须和 XML 标签名严格一致(大小写敏感),或用
[XmlElement("book-title")]显式映射 - 嵌套结构需对应类层级:
<root><item><name>xxx</name></item></root>要求Root类含Item属性,Item类含Name属性 - 空元素如
<price />对应int?或string,不能直接映射到int(会抛异常)
命名空间、编码声明、空白文本节点、流生命周期管理——这些地方不显眼,但一踩一个准。与其反复试 XPath,不如先 dump 出实际 DOM 结构看一眼。


















