xmlreader.create(string) 不支持直接传字符串,须用 stringreader 包装;需设 dtdprocessing.prohibit 和 xmlresolver=null 防 xxe;读取文本应避免直接用 innertext,推荐 readtofollowing + readelementcontentasstring。

XmlReader.Create(string) 不能直接用,必须套一层 StringReader
直接传字符串给 XmlReader.Create("...") 会报错:NotSupportedException: This XmlReader implementation does not support reading from a string. 因为 Create 的重载里没有接受 string 类型的版本——它只认流(Stream)、文本阅读器(TextReader)或 URI。
正确做法是把 XML 字符串包进 StringReader,再传给 Create:
var xml = "<root><item id=\"1\"/></root>"; using var reader = XmlReader.Create(new StringReader(xml));
-
StringReader是TextReader的子类,符合Create的参数要求 - 别用
new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)))—— 多余、慢、还可能因 BOM 或编码不一致出问题 - 如果 XML 来自用户输入或配置项,记得先做基础校验(比如非空、是否以 Create 阶段才崩
XmlReaderSettings 要设成 DtdProcessing.Prohibit 才安全
默认设置下,XmlReader 可能尝试解析外部 DTD,导致 XXE 攻击或网络请求失败(比如读到 .. SYSTEM "http://xxx"> 就卡住或抛异常)。
生产环境必须显式禁用:
var settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null
};
using var reader = XmlReader.Create(new StringReader(xml), settings);
- 漏设
DtdProcessing.Prohibit是常见疏忽,尤其本地测试时没暴露问题,上线后遇到恶意 XML 就挂 -
XmlResolver = null是双重保险,防止某些老版本 .NET 忽略DtdProcessing - 如果真要支持 DTD(极少见),改用
Parse模式并自定义XmlResolver,但绝大多数场景不需要
Read() 后别直接读 InnerText,容易跳过节点或重复读
新手常写 reader.Read(); Console.WriteLine(reader.InnerText);,结果要么为空,要么内容错位。因为 Read() 移动到下一个节点,但不保证停在有文本内容的节点上(比如停在 StartElement 上,InnerText 就是空)。
- 想取某个元素的文本值,先用
ReadToFollowing("elementName")定位,再用ReadElementContentAsString() - 想遍历所有文本节点,用
if (reader.NodeType == XmlNodeType.Text) { ... }判断,而不是依赖InnerText -
InnerText是“当前节点及其所有子节点的合并文本”,对嵌套结构容易误读;Value更轻量,但只对Text、Attribute等特定节点类型有效
StringReader 不支持 Seek,XmlReader 无法回退
StringReader 是单向流,一旦 XmlReader 读过去,就不能 reader.MoveToFirstAttribute() 或 reader.ReadToPrevious() —— 这些方法会抛 InvalidOperationException。
- 需要多次遍历 XML?别反复用同一个
StringReader,每次新建一个:XmlReader.Create(new StringReader(xml)) - 想随机访问节点,考虑用
XDocument.Load(new StringReader(xml)),虽然内存开销大,但灵活得多 - 性能敏感场景(如高频解析小 XML),可缓存
XDocument实例,但注意线程安全:XDocument不是线程安全的,别共享实例
最麻烦的其实是调试:XmlReader 没有“当前 XML 片段”快照功能,出错时只能靠 reader.Name、reader.Depth 和 reader.LineNumber 拼上下文,建议解析前先打日志输出前 200 字符。









