为啥 XmlNamespaceManager 为 HasNamespace 返回不一致的结果?

Posted

技术标签:

【中文标题】为啥 XmlNamespaceManager 为 HasNamespace 返回不一致的结果?【英文标题】:Why does XmlNamespaceManager return inconsistent results for HasNamespace?为什么 XmlNamespaceManager 为 HasNamespace 返回不一致的结果? 【发布时间】:2021-04-20 15:17:45 【问题描述】:

我正在尝试处理 XML 文档并确定其中定义了哪些命名空间,但我无法从 XmlNamespaceManager.HasNamespace 获得一致的结果。在读取文档时,HasNamespace 将返回 false,即使它仍被声明并在范围内。

示例代码:

    var ctx = new XmlParserContext(null, new XmlNamespaceManager(new NameTable()), null, XmlSpace.None);
    var set = new XmlReaderSettings()  IgnoreComments = true, IgnoreProcessingInstructions = true, IgnoreWhitespace = true ;

    using (var xml = new StringReader(
        "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
        "<rdf:RDF " +
        "  xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"> " +
        "  <rdf:Description rdf:about=\"x\" /> " +
        "</rdf:RDF>"))
    using (var rdr = XmlReader.Create(xml, set, ctx))
    
        rdr.MoveToContent();

        Console.WriteLine(rdr.Name);
        Console.WriteLine(rdr.LookupNamespace("rdf"));
        Console.WriteLine(ctx.NamespaceManager.HasNamespace("rdf"));    // True
        
        rdr.Read();
        
        Console.WriteLine(rdr.Name);
        Console.WriteLine(rdr.LookupNamespace("rdf"));
        Console.WriteLine(ctx.NamespaceManager.HasNamespace("rdf"));    // False
        
        rdr.Read();
        
        Console.WriteLine(rdr.Name);
        Console.WriteLine(rdr.LookupNamespace("rdf"));
        Console.WriteLine(ctx.NamespaceManager.HasNamespace("rdf"));    // True
    

Fiddle

【问题讨论】:

【参考方案1】:

当阅读器输入每个新元素时,它会在命名空间管理器上调用PushScope。一旦它离开元素(通过自闭合标签的结尾或相应的结束标签),它就会调用PopScope

HasNamespace,与命名空间管理器的其他一些成员不同,只回答当前范围的问题。

获取一个值,该值指示提供的前缀是否具有为当前推送范围定义的命名空间。

(我的重点

一般而言,您不应该过多地使用命名空间前缀,除非您实际上是在自己执行解析1,而不是利用现有工具。它是元素名称 (RDF) 和命名空间 (http://www.w3.org/1999/02/22-rdf-syntax-ns#\) 的组合,唯一地定义了元素的类型 - 前缀可以更改(前提是它在其有效的文档范围内始终如一地完成) ) 而不改变 XML 的信息内容


如果你创建了这个类,你可以自己看到:

class LoggingNamespaceManager : XmlNamespaceManager

    public LoggingNamespaceManager (XmlNameTable table) : base(table)
    

    

    public override void PushScope()
    
        Console.WriteLine("Push");
        base.PushScope();
    

    public override bool PopScope()
    
        Console.WriteLine("Pop");
        return base.PopScope();
    

并在示例的第一行实例化它而不是 XmlNamespaceManager


1请不要。已经有足够多的脆弱的“XML”解析器建立在关于 XML 的无效假设之上。按照您目前的做法,使用框架中提供的工具。

【讨论】:

我曾认为父级中定义的任何命名空间都会自动流向子级,但我想情况并非如此。至于前缀,很公平,但我正在使用一个定义必须可用的前缀的标准。

以上是关于为啥 XmlNamespaceManager 为 HasNamespace 返回不一致的结果?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 math.inf 是浮点数,为啥我不能将其转换为整数?

为啥指数推送令牌为空

为啥我的 Entity Framework Code First 代理集合为空,为啥我不能设置它?

为啥 libman.json 被创建为“内容”以及为啥它具有“如果较新则复制”属性?

为啥要转换为接口?

为啥文档为空?