【问题标题】:Handle XML with and without a Default Namespace使用和不使用默认命名空间处理 XML
【发布时间】:2014-01-18 20:30:07
【问题描述】:

我正在用 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# 在默认命名空间方面存在问题),不如问我要执行哪些检查以确保涵盖所有场景。

【问题讨论】:

    标签: c# xml xml-namespaces


    【解决方案1】:

    人们会假设 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 中获取映射可能是安全的,除非您基于 XML 构建 XPath 示例:

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

    请注意,XML 可能对所有命名空间使用单个命名空间前缀(空前缀或任何其他前缀)。 IE。从 XML 的角度来看,以下 XML 与前面的示例相同,即使它使用前缀:

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

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

    【讨论】:

    • xml 将始终具有“someNamespace”,但为其分配任何前缀是不合法的(xmlns:ns0=someNamespace,xmlns:urn=someNamespace)。然后将命名空间添加到命名空间管理器会中断,因为我试图向它添加错误的前缀。
    • @Joe - 显然这不是有用的答案 - 我很快就会删除它。其他人应该尝试解释 XML 和 XPath 中的前缀之间没有关系。很抱歉浪费您的时间。
    • 不,您的回答很有帮助。我只是仍在尝试弄清楚如何为未知前缀编码。
    • @Joe - 我会保留它而不是......但看起来它仍然没有达到可能的点:唯一重要的是命名空间,无论你以何种方式命名前缀都无关紧要它产生有效的 XPath/有效的 XML。如果您假装 XML 中没有前缀并且每个前缀都替换为完整的命名空间,这可能会更容易理解...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多