为什么 XmlNamespaceManager return 与 HasNamespace 的结果不一致?
Why does XmlNamespaceManager return inconsistent results for HasNamespace?
我正在尝试处理 XML 文档并确定其中定义了哪些命名空间,但我无法从 XmlNamespaceManager.HasNamespace 获得一致的结果。当它正在阅读文档时,HasNamespace 将 return 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
}
当 reader 进入每个新元素时,它会调用命名空间管理器上的 PushScope
。一旦它离开元素(通过自闭合标签或相应的结束标签的末尾),它就会调用 PopScope
.
HasNamespace
,不像命名空间管理器的其他一些成员,只回答当前范围的问题。
Gets a value indicating whether the supplied prefix has a namespace defined for the current pushed scope.
(我的重点)
一般来说,你不应该那么多地使用命名空间前缀,除非你实际上是在自己执行解析1 而不是利用现有工具。它是元素名称 (RDF
) 和命名空间 (http://www.w3.org/1999/02/22-rdf-syntax-ns#\
) 的组合,唯一定义了元素的类型 - 前缀可以更改(前提是它在整个文档范围内一致地完成它是有效的)而不改变 XML.
的 信息内容
如果你创建这个,你可以自己看到这个class:
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 的无效假设之上的。像您目前所做的那样使用框架中提供的工具。
我正在尝试处理 XML 文档并确定其中定义了哪些命名空间,但我无法从 XmlNamespaceManager.HasNamespace 获得一致的结果。当它正在阅读文档时,HasNamespace 将 return 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
}
当 reader 进入每个新元素时,它会调用命名空间管理器上的 PushScope
。一旦它离开元素(通过自闭合标签或相应的结束标签的末尾),它就会调用 PopScope
.
HasNamespace
,不像命名空间管理器的其他一些成员,只回答当前范围的问题。
Gets a value indicating whether the supplied prefix has a namespace defined for the current pushed scope.
(我的重点)
一般来说,你不应该那么多地使用命名空间前缀,除非你实际上是在自己执行解析1 而不是利用现有工具。它是元素名称 (RDF
) 和命名空间 (http://www.w3.org/1999/02/22-rdf-syntax-ns#\
) 的组合,唯一定义了元素的类型 - 前缀可以更改(前提是它在整个文档范围内一致地完成它是有效的)而不改变 XML.
如果你创建这个,你可以自己看到这个class:
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 的无效假设之上的。像您目前所做的那样使用框架中提供的工具。