【问题标题】: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

【问题讨论】:

    标签: c# xml xmlreader


    【解决方案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 的无效假设之上。按照您目前的做法,使用框架中提供的工具。

    【讨论】:

    • 我曾认为父级中定义的任何命名空间都会自动流向子级,但我想情况并非如此。至于前缀,很公平,但我正在使用一个定义必须可用的前缀的标准。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多