Skip to main content
 首页 » 编程设计

.net之为什么需要 XmlNamespaceManager

2024年02月27日12www_RR

对于为什么(至少在 .Net Framework 中),我已经有点干巴巴地想出了为什么有必要使用 XmlNamespaceManager 。为了在执行 XPath 查询时处理 namespace (或相当笨重和冗长的 [local-name()=... XPath 谓词/函数/其他)。我确实理解为什么命名空间是必要的或至少是有益的,但是为什么它如此复杂?

为了查询简单的 XML 文档(无命名空间)...

<?xml version="1.0" encoding="ISO-8859-1"?> 
<rootNode> 
   <nodeName>Some Text Here</nodeName> 
</rootNode> 

...可以使用类似 doc.SelectSingleNode("//nodeName") 的内容(将匹配 <nodeName>Some Text Here</nodeName> )

谜团#1:我的第一个烦恼——如果我理解正确的话——是仅仅添加一个对父/根标签的命名空间引用(无论是用作一部分)是否有子节点标签),如下所示:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<rootNode xmlns="http://example.com/xmlns/foo"> 
   <nodeName>Some Text Here</nodeName> 
</rootNode> 

...需要几行额外的代码才能获得相同的结果:

Dim nsmgr As New XmlNamespaceManager(doc.NameTable) 
nsmgr.AddNamespace("ab", "http://example.com/xmlns/foo") 
Dim desiredNode As XmlNode = doc.SelectSingleNode("//ab:nodeName", nsmgr) 

...本质上是梦想一个不存在的前缀(“ab”)来查找甚至不使用前缀的节点。 这有什么意义? doc.SelectSingleNode("//nodeName") 有什么问题(概念上) ?

谜团 #2:假设您有一个使用前缀的 XML 文档:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<rootNode xmlns:cde="http://example.com/xmlns/foo" xmlns:feg="http://example.com/xmlns/bar"> 
   <cde:nodeName>Some Text Here</cde:nodeName> 
   <feg:nodeName>Some Other Value</feg:nodeName> 
   <feg:otherName>Yet Another Value</feg:otherName> 
</rootNode> 

...如果我理解正确,您必须将两个命名空间添加到 XmlNamespaceManager ,为了对单个节点进行查询...

Dim nsmgr As New XmlNamespaceManager(doc.NameTable) 
nsmgr.AddNamespace("cde", "http://example.com/xmlns/foo") 
nsmgr.AddNamespace("feg", "http://example.com/xmlns/bar") 
Dim desiredNode As XmlNode = doc.SelectSingleNode("//feg:nodeName", nsmgr) 

... 在这种情况下,为什么我需要(概念上)命名空间管理器?

*****已编辑到下面的评论中****

编辑已添加: 我修改和完善的问题是基于我认为大多数情况下 XmlNamespaceManager 的明显冗余以及使用命名空间管理器来指定前缀到 URI 的映射:

当源文档中明确说明命名空间前缀(“cde”)到命名空间 URI(“http://example.com/xmlns/foo”)的直接映射时:

...<rootNode xmlns:cde="http://example.com/xmlns/foo"... 

程序员在进行查询之前重新创建该映射的概念需求是什么?

请您参考如下方法:

基本点(正如 Kev, above 所指出的),是命名空间 URI 是命名空间的重要组成部分,而不是命名空间前缀,前缀是一种“任意便利”

至于为什么需要命名空间管理器,而不是使用文档来解决它,我可以想到两个原因。

原因 1

如果只允许向 documentElement 添加 namespace 声明(如您的示例中所示),那么 selectSingleNode 仅使用定义的任何内容确实很简单。

但是,您可以在文档中的任何元素上定义命名空间前缀,并且命名空间前缀不会唯一绑定(bind)到文档中的任何给定命名空间。考虑以下示例

<w xmlns:a="mynamespace"> 
  <a:x> 
    <y xmlns:a="myOthernamespace"> 
      <z xmlns="mynamespace"> 
      <b:z xmlns:b="mynamespace"> 
      <z xmlns="myOthernamespace"> 
      <b:z xmlns:b="myOthernamespace"> 
    </y> 
  </a:x> 
</w> 

在此示例中,您希望 //z//a:z//b:z 返回什么?如果没有某种外部 namespace 管理器,您将如何表达这一点?

原因 2

它允许您对任何等效文档重用相同的 XPath 表达式,而无需了解有关所使用的命名空间前缀的任何信息。

myXPathExpression = "//z:y" 
doc1.selectSingleNode(myXPathExpression); 
doc2.selectSingleNode(myXPathExpression); 

文档1:

<x> 
  <z:y xmlns:z="mynamespace" /> 
</x> 

文档2:

<x xmlns"mynamespace"> 
  <y> 
</x> 

为了在没有 namespace 管理器的情况下实现后一个目标,您必须检查每个文档,为每个文档构建自定义 XPath 表达式。