读取XML文件无唯一正确方式,需据结构、性能及反序列化需求选择:XmlDocument适合随机访问但耗内存;XmlSerializer适合对象映射但要求严格匹配;XmlTextReader适合大文件流式处理;XPathDocument适合复杂只读查询。

直接读取 XML 文件没有“唯一正确方式”,选哪种取决于你手里的 XML 结构、性能要求,以及是否需要反序列化为对象。用错方法会导致代码冗长、易崩、难维护。
XmlDocument 适合结构清晰、需随机访问节点的场景
它把整个 XML 加载进内存构建成 DOM 树,支持 XPath 查询和任意节点跳转。但文件大时会吃内存,且不支持流式读取。
- 必须确保 XML 格式合法,否则
doc.Load()会直接抛XmlException -
SelectNodes("/Table/row")返回的是XmlNodeList,不是强类型集合,遍历时要手动取Attributes["xxx"]或["ElementName"].InnerText - 读取属性前务必检查
item.Attributes["Version"] != null,否则空引用异常很常见 - 如果 XML 有命名空间,
SelectNodes必须传入XmlNamespaceManager,否则查不到任何节点
XmlSerializer 适合已知类型、想直接映射为 C# 对象的情况
它不关心 XML 结构细节,只认类定义和公共属性。前提是类必须有无参构造函数,属性得是 public,且字段名/属性名要和 XML 元素名严格匹配(或用 [XmlElement("Title")] 显式标注)。
-
XmlSerializer只反序列化 public 字段和属性,private 或 internal 的一律忽略 - 若 XML 中某个字段缺失,对应属性会被设为默认值(如
int是 0,string是null),不会报错——这容易掩盖数据问题 - 不能处理同名但类型不同的嵌套结构(比如
<item>123</item>和<item><name>abc</name></item>混用时会失败) - 反序列化后务必校验关键字段是否为空或非法,比如
overview.Title?.Trim() == ""
XmlTextReader 适合大文件、只做简单扫描或过滤的场景
它是只进、只读、低开销的流式读取器,内存占用恒定,但没法回退、也不能 XPath 查询。适合日志解析、配置预检这类单次线性处理。
-
reader.Read()返回false表示到底,但中间可能因格式错误提前中断,建议用 try/catch 包住整个 while 循环 - 判断当前节点类型要用
reader.NodeType == XmlNodeType.Element,别只靠reader.Name匹配,否则注释、CDATA、文本节点都会干扰逻辑 - 读取元素内容别直接用
reader.Value,它在不同节点类型下行为不一致;应配合ReadElementContentAsString()或ReadInnerXml()明确语义 - 记得调用
reader.Close()或用using语句块,否则文件句柄可能泄漏
XPathDocument + XPathNavigator 适合复杂查询但不想写太多样板代码
它比 XmlDocument 更轻量,专为 XPath 查询优化,适合需要条件筛选、位置计算、跨层级匹配的场景。但它不支持修改,纯只读。
-
XPathDocument构造时若传入非法路径或不可读文件,会直接抛IOException或XmlException,不延迟到查询时才报 -
XPathNavigator.Select("count(//book[price > 100])")这类聚合表达式返回的是XPathNodeIterator,需调用MoveNext()才能取值 - 字符串比较要写成
name = 'ABC',不能用==;大小写敏感,没加translate()就别指望忽略大小写 - 它不缓存原始 XML 文本,
XPathNavigator.InnerXml是动态生成的,频繁调用有性能开销
真正难的不是选哪个类,而是搞清你的 XML 是不是总能保证格式一致、有没有命名空间、要不要容错、要不要验证业务规则。这些决定了后续所有代码的健壮性边界。


















