为什么XmlNamespaceManager的HasNamespace方法返回结果不一致?

3
我正在尝试处理一个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个回答

3
当读者进入每个新元素时,它将在命名空间管理器上调用PushScope。一旦通过自闭合标记的结尾或相应的结束标记离开该元素,它就会调用PopScopeHasNamespace与命名空间管理器的其他成员不同,它仅针对当前作用域回答问题。

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

(由我强调)
一般来说,除非你正在进行解析而不是利用现有的工具,否则你不应该过多地使用命名空间前缀。元素名称(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


请不要这样做。已经有足够多脆弱的“XML”解析器了,它们基于无效的关于XML的假设构建。像您目前正在使用的那样,请使用框架中提供的工具。

我曾经认为在父级中定义的任何命名空间都会自动流向子级,但我想这并不是这样。至于前缀,也可以理解,但我正在使用一个定义了必须可用的前缀的标准。 - mford

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接