C#解析XML时无法获取属性中ENTITY外部实体路径值问题
问题原因
Ref属性读取到实体名extern1而非路径test.txt是XML规范下的预期行为:
- 声明为
ENTITY类型的属性,存储的取值本身就是未解析实体的名称,不会自动替换为实体绑定的资源路径 - DTD中定义的
extern1是带NDATA标记的未解析外部实体,这类实体不会像普通内部实体extern2那样在文档加载阶段被自动展开替换,.NET内置XML解析器默认不会将这类实体的元数据直接暴露在属性节点的常规取值属性上。 - 调用属性的
InnerText/Value方法只能获取属性中填写的实体名称,无法直接读取DTD中声明的实体绑定路径。
实现方法
要获取未解析实体绑定的系统路径,需要在DTD加载完成后,从文档的DTD节点维护的实体集合中,按照属性读取到的实体名查找对应实体对象,再读取其SystemLiteral属性即可,修正后的代码如下:
var xmlSettings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse, ValidationType = ValidationType.DTD, XmlResolver = new XmlUrlResolver() }; var doc = new XmlDocument(); using ( var xmlReader = XmlReader.Create(@"C:\Temp\test.xml", xmlSettings) ) { doc.Load(xmlReader); } var externNode = doc.SelectSingleNode("//EXTERN"); var extern_Content = externNode.InnerText; // 读取Ref属性存储的实体名称 string entityName = externNode.Attributes["Ref"].InnerText; // 从DTD声明的实体集合中匹配目标实体 XmlEntity targetEntity = doc.DocumentType.Entities.GetNamedItem(entityName) as XmlEntity; if (targetEntity != null) { // SystemLiteral即为外部实体绑定的路径test.txt string extern_Ref = targetEntity.SystemLiteral; // 若为PUBLIC类型声明的实体,可读取PublicLiteral属性获取公共标识符 }
注意事项
- 必须保持
XmlReaderSettings中DtdProcessing.Parse配置开启,否则DTD中自定义声明的实体不会被加载,无法从DocumentType.Entities集合中查到目标实体 - 若DTD中声明的是相对路径,
SystemLiteral会原样返回DTD中填写的相对路径字符串,需要绝对路径时可结合XML文件所在目录自行拼接,或通过XmlResolver解析为完整URI - 带NDATA标记的未解析外部实体才会以实体名的形式存储在ENTITY类型属性中,普通内部解析实体(比如示例中的
extern2)会在加载时被自动展开替换为实体内容,这也是示例中节点内部文本读取结果符合预期的原因。
内容的提问来源于stack exchange,提问作者ZTHawk
相关产品推荐
相关产品推荐

