C#:XmlDocument与XDocument处理无效十六进制字符的差异及咨询
XDocument与XmlDocument处理含十六进制实体XML的问题
我们在使用XDocument处理接收的XML文档时,遇到了由XmlDocument生成的、包含十六进制实体表达式的文档,XDocument.Parse()会直接拒绝处理这类文档。
XmlDocument的表现则完全不同:它既能将传入的控制字符编码生成含十六进制实体的XML文档,也能正常解析包含这些实体的XML;而XDocument无论是创建包含控制字符的文档,还是解析含十六进制实体的文档,都会抛出异常。
示例代码
static void Main(string[] args) { string message = "Hello, \x1EWorld!"; // 包含控制码1E的字符串 // 这段代码正常执行 - 创建包含控制字符的XML文档 XmlDocument xmlDoc = new XmlDocument(); XmlElement root = xmlDoc.CreateElement("greeting"); xmlDoc.AppendChild(root); root.InnerText = message; Console.WriteLine(xmlDoc.OuterXml); // 输出: <greeting>Hello, World!</greeting> // 这段代码执行失败 - XDocument创建含控制字符的文档 try { XDocument xdoc = new XDocument( new XElement("greeting", message) ); Console.WriteLine(xdoc.ToString()); } catch (Exception ex) { Console.WriteLine($"XDocument creation error: {ex}"); } // 这段代码正常执行 - XmlDocument加载含十六进制实体的XML string xmlWithEscapedHexEntity = xmlDoc.OuterXml; // <greeting>Hello, World!</greeting> xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xmlWithEscapedHexEntity); Console.WriteLine(xmlDoc.OuterXml); // 这段代码执行失败 - XDocument解析含十六进制实体的XML try { XDocument xDoc = XDocument.Parse(xmlWithEscapedHexEntity); Console.WriteLine(xDoc.ToString()); } catch (Exception ex) { Console.WriteLine($"XDocument parse failure: {ex}"); } Console.ReadLine(); }
问题解答
1. 如何让XDocument处理这类含十六进制实体的XML?
有两种可靠的方法,比正则预处理更安全:
用XmlDocument做中间转换:先通过XmlDocument加载XML字符串,再转换为XDocument。XmlDocument会先处理掉十六进制实体,转换后的XDocument就能正常操作:
string xmlWithHexEntity = "<greeting>Hello, World!</greeting>"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xmlWithHexEntity); using (var reader = new XmlNodeReader(xmlDoc)) { XDocument xDoc = XDocument.Load(reader); // 后续正常操作XDocument }关闭XmlReader的字符检查:创建XmlReader时设置
CheckCharacters = false,这样XDocument加载时会跳过严格的字符规范检查,直接处理文档:XmlReaderSettings settings = new XmlReaderSettings(); settings.CheckCharacters = false; using (XmlReader reader = XmlReader.Create(new StringReader(xmlWithHexEntity), settings)) { XDocument xDoc = XDocument.Load(reader); }注意:关闭字符检查后,控制字符会保留在文档中,后续处理时需注意潜在问题。
不建议用正则表达式预处理,因为XML结构复杂(比如CDATA区块、属性值等),正则容易误修改合法内容,导致XML损坏。
2. 为什么XDocument和XmlDocument有行为差异?
- XmlDocument的设计兼容旧场景:它是.NET早期的XML处理组件,设计时更偏向兼容性,允许处理一些不符合严格XML规范的内容。比如XML 1.0规范中禁止的控制字符(U+0000到U+001F,除了换行、回车、制表符),XmlDocument会自动编码和解码,不会抛出异常。
- XDocument严格遵循XML规范:作为LINQ to XML的核心组件,XDocument严格执行XML 1.0的规范,明确禁止这类控制字符出现在文档中(无论是直接字符还是实体引用)。一旦检测到不符合规范的内容,就会抛出异常,确保生成和解析的XML都是合法的。
内容的提问来源于stack exchange,提问作者retired
相关产品推荐
相关产品推荐

