使用System.Xml.XmlReader读取含非法XML处理指令数据的问题问询
问题根因
你遇到的报错是因为服务端返回的开头<? LLSD/XML ?>不符合XML处理指令(PI)的语法规范:XML要求处理指令开头<?之后必须紧跟PI名称,不能有空格。即便你在XmlReaderSettings里开启了IgnoreProcessingInstructions = true,XmlReader也会先校验PI的语法结构再执行忽略逻辑,语法校验不通过会直接抛出异常,该配置不会生效。
另外你现有的代码还存在一个明显问题:定义了XmlReaderSettings但没有传入XmlReader.Create方法,所有你配置的校验规则实际都没有生效。
解决方案1:预处理跳过非法开头行(推荐)
因为你的非法处理指令是单独占第一行,其余内容都是规范XML,最简单的方式是先读取并丢弃第一行,再用剩下的流创建XmlReader即可,代码示例如下:
public static OSD DeserializeLLSDXml(Stream xmlStream) { XmlReaderSettings settings = new XmlReaderSettings { ValidationType = ValidationType.None, CheckCharacters = false, IgnoreComments = true, IgnoreProcessingInstructions = true, DtdProcessing = DtdProcessing.Prohibit }; // 注意匹配你实际的编码,默认按UTF-8处理,有需要可自行调整 StreamReader sr = new StreamReader(xmlStream, Encoding.UTF8); string firstLine = sr.ReadLine(); // 判断第一行是否为非法处理指令,不是的话需要把已读取的第一行加回内容 if (!firstLine.TrimStart().StartsWith("<? LLSD/XML")) { var remainingContent = firstLine + Environment.NewLine + sr.ReadToEnd(); var remainingStream = new MemoryStream(Encoding.UTF8.GetBytes(remainingContent)); remainingStream.Position = 0; sr = new StreamReader(remainingStream); } // 注意此处要传入settings,配置才会生效 using (XmlReader xrd = XmlReader.Create(sr, settings)) { return DeserializeLLSDXml(xrd); } }
解决方案2:全局过滤非法处理指令(适配PI不独占一行的场景)
如果你的非法处理指令可能和其他XML内容在同一行,可以用字符串替换的方式先把所有<? LLSD/XML ?>片段移除再解析:
public static OSD DeserializeLLSDXml(Stream xmlStream) { XmlReaderSettings settings = new XmlReaderSettings { ValidationType = ValidationType.None, CheckCharacters = false, IgnoreComments = true, IgnoreProcessingInstructions = true, DtdProcessing = DtdProcessing.Prohibit }; string xmlContent = new StreamReader(xmlStream, Encoding.UTF8).ReadToEnd(); // 替换所有非法处理指令片段 xmlContent = xmlContent.Replace("<? LLSD/XML ?>", string.Empty); var processedStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlContent)); processedStream.Position = 0; using (XmlReader xrd = XmlReader.Create(processedStream, settings)) { return DeserializeLLSDXml(xrd); } }
注意事项
- 两种方案都需要注意匹配你实际的XML编码,如果服务端返回的不是UTF-8,需要调整Encoding参数
- 方案1的性能更优,不需要把整个XML内容读入内存,适合大XML场景
内容的提问来源于stack exchange,提问作者Cinder Biscuits
相关产品推荐
相关产品推荐

