使用和不使用默认命名空间处理XML

时间:2014-01-18 20:30:08

标签: c# xml xml-namespaces

我正在用C#编写一段代码,它将接收XML并将提取一些值。当我收到的XML有一个默认命名空间时,我必须使用XmlNamespaceManager。

XmlDocument requestXml = new XmlDocument();
requestXml.LoadXml(request);
XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(requestXml.NameTable);
xmlNamespaceManager.AddNamespace("ns0", requestXml.DocumentElement.NamespaceURI);
metadata.Identifier = requestXml.SelectSingleNode("//ns0:Identifier[1]", xmlNamespaceManager).InnerText;

但是当命名空间有一个前缀而不是这个代码中断时,它可以在没有命名空间管理器的情况下工作。

XmlDocument requestXml = new XmlDocument();
requestXml.LoadXml(request);
metadata.Identifier = requestXml.SelectSingleNode("//Identifier[1]").InnerText;

我希望知道xml名称空间是否有前缀是否合理?如果没有,我如何构建更健壮的代码,而不关心命名空间是否有前缀?非常感谢任何帮助。

更新

我的理解是这三者是一样的 例1:

<Node1 xmlns="myNamespace">
    <Node2>
        <Node3></Node3>
    </Node2>
</Node1>

例2:

<ns0:Node1 xmlns:ns0="myNamespace">
    <Node2>
        <Node3></Node3>
    </Node2>
</ns0:Node1>

示例3:

<ns0:Node1 xmlns:ns0="myNamespace">
    <ns0:Node2>
        <ns0:Node3></ns0:Node3>
    </ns0:Node2>
</ns0:Node1>

而不是询问C#如何对待这些(我知道C#在使用默认命名空间时遇到问题),更好的问题是我要执行哪些检查以确保覆盖所有方案。

1 个答案:

答案 0 :(得分:0)

可以假设XML中的名称空间前缀与XPath中的名称空间前缀之间存在很强的关系,但没有。

XML中节点的命名空间前缀:可以是空的,空前缀映射到当前默认的命名空间。 当前元素的默认命名空间可以是空命名空间(如果当前/父节点上没有xmlns="urn:somenamespace"),或者如果存在xmlns,则可以是某个特定命名空间。

样品:

<root>
   <child1 xmlns="urn:ns1">
       <inner xmlns="urn:reallyDeep" />
   </child1>
   <child2 />
<root>

空名称空间前缀映射到:

  • root - 空命名空间(默认)
  • child1 - urn:ns1,完整节点名称可以表示为{urn:ns1}child1
  • child2 - 来自父(root
  • 的空名称空间
  • inner - urn:reallyDeep因为它已在xmlns:的节点上重新定义。

现在XPath名称空间前缀有点简单,因为空前缀始终映射到空名称空间。

要在上面的示例中选择inner节点,需要从3个名称空间中选择节点:空,urn:ns1urn:reallyDeep。因此,名称空间管理器需要使用3个前缀构建。默认空的一个总是在那里,所以需要再添加两个。请注意,XPath中的前缀与XML中的前缀无关 - 通常的做法是匹配某些“众所周知的”命名空间(如xsi)的前缀,但它绝对是个人选择。

 p1 -> urn:ns1
 p2 -> urn:reallyDeep

 /root/p1:child1/p2:child2

编写代码时,除非根据XML构建XPath示例,否则显式定义映射可能是安全的,而不是尝试从XML中获取映射:

 xmlNamespaceManager.AddNamespace("p1", "urn:ns1");
 xmlNamespaceManager.AddNamespace("ns0", "urn:reallyDeep");

请注意,XML可以为所有命名空间使用单个命名空间前缀(空前缀或任何其他命名空间)。即以下XML在XML的观点与之前的示例相同,即使它使用前缀:

<root>
   <a:child1 xmlns="urn:ns1">
       <a:inner xmlns:a="urn:reallyDeep" />
   </a:child1>
   <child2 />
<root>

请注意,如果您不关心名称空间和前缀(在这种情况下您实际上没有正确使用XML),则可以使用local-name XPath函数来比较名称。