从xml文档中读取命名空间

时间:2010-08-16 14:31:52

标签: xml xsd c++-cli xmldocument

如何从XML文档中读取命名空间?

<fx:FIBEX xmlns:fx="http://www.asam.net/xml/fbx" xmlns:can="http://www.asam.net/xml/fbx/can" xmlns:flexray="http://www.asam.net/xml/fbx/flexray"      
    xmlns:ho="http://www.asam.net/xml" xmlns:ni="http://www.ni.com/xnet"    
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
    xsi:schemaLocation="http://www.asam.net/xml/fbx/all http://www.asam.net/xml/fbx/2_0_1/xsd/fibex4multiplatform.xsd"     
     VERSION="2.0.1">

如何从此根元素中读取命名空间?

实际上,最终的问题是“如何使用xPath检索节点

//fx:ELEMENTS/fx:CLUSTERS/fx:CLUSTER 

我已尝试使用该字符串的XmlDocument.SelectSingleNode(),但这给了我一些关于XmlNamespaces的错误,我在google上发现你需要有一个XmlNamespaceManager。

1 个答案:

答案 0 :(得分:3)

您的问题实际上似乎包含两个不同的问题:

  1. 如何选择在某个命名空间中声明的元素?
  2. 如何选择元素的命名空间节点?
  3. 问题1

    要选择某个命名空间中的节点,您需要指定prefix-namespace映射。所有XPath处理器都允许这样做但是如何完成取决于实现。通常,这意味着创建一对 - 前缀和URI - 然后将此对添加为名称空间上下文。 URI非常重要。它必须与元素的名称空间URI完全相同。前缀不需要与文档中使用的前缀相同,它可以是任何内容,但即使元素位于默认命名空间中,也需要前缀,因此前缀无需固定。

    在XPath解析器知道所需的命名空间后,您可以像在问题中一样选择元素://fx:ELEMENTS/fx:CLUSTERS/fx:CLUSTER。确保使用的是映射中使用的相同前缀(如果前缀与文档中的前缀不同)。请注意,在XPath表达式中,始终假定没有前缀的元素具有 no namespace ,因此即使从默认命名空间中选择元素,也需要在XPath表达式中使用名称空间前缀。

    对于脏黑客,您也可以尝试完全避免使用元素名称。在Xpath *匹配所有元素节点和node()所有节点。您可以通过创造性地使用使用name()local-name()position()last()等功能的谓词来缩小选择范围。例如,XPath表达式//*[name()='fx:CLUSTER']选择所有具有前缀“fx”和本地名称“CLUSTER”的元素,即使没有prefix-namespace映射也可以。请注意,虽然在XML中,前缀不能保证保持不变,并且它们也可以在文档中重复使用/覆盖,以便相同的前缀引用文档不同部分中的不同URI。

    问题2

    使用namespace::轴选择命名空间节点。命名空间节点名称的本地部分是名称空间前缀,字符串值是名称空间URI。默认命名空间的节点具有空名称。您可以选择具有带有XPath表达式//namespace::*[.=http://example.com/ns]的URI http://example.com/ns的所有命名空间节点,并选择前缀为“px:”的所有命名空间节点,并使用//namespace::*[name()='px']。与属性节点一样,命名空间节点不是它所属元素的子节点,但该元素是该节点名称节点的父节点。使用parent::轴获取命名空间节点的所有者。

    命名空间不需要在根元素中声明(尽管这是常见的且非常合理),但它们可以在任何元素中声明。搜索根元素的命名空间节点并不能保证您知道本文档中使用的所有命名空间URI和前缀。

    问题是所有元素都有一个或多个命名空间节点,而不管该元素是否具有显式的命名空间声明。元素具有一组命名空间节点,一个用于默认命名空间(如果它在此元素的范围内),另一个用于此元素范围内的每个前缀,包括xml前缀。下面是不同情况下命名空间节点的代码示例。

    此示例包含3个文件:具有不同命名空间的XML文档,用于打印每个元素的命名空间节点值的XSLT文档以及XSLT文档的输出。

    已处理的XML文档

    <root xmlns:ns1="http://example.com/namespace-1">
     <nothing/>
     <default xmlns="http://example.com/default">
      <override xmlns=""/>
     </default>
     <ns1:namespace-1 ns1:attribute-1="x" attribute-2="y"/>
     <ns2:namespace-2 xmlns:ns2="http://example.com/namespace-2"/>
    </root>
    

    XSLT文档

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
     <xsl:output encoding="utf-8" method="text"/>
    
     <xsl:template match="/">
      <xsl:text>Find and print all element names and namespace nodes&#10;&#10;</xsl:text>
      <xsl:apply-templates select="//*|//@*"/>
      <xsl:text>End of tests&#10;</xsl:text>
     </xsl:template>
    
     <xsl:template match="*|@*">
      <xsl:text>name          = "</xsl:text>
      <xsl:value-of select="name(.)"/>
      <xsl:text>"&#10;</xsl:text>
      <xsl:text>namespace URI = "</xsl:text>
      <xsl:value-of select="namespace-uri(.)"/>
      <xsl:text>"&#10;</xsl:text>
      <xsl:text>This node has </xsl:text>
      <xsl:value-of select="count(./namespace::*)"/>
      <xsl:text> namespace nodes:&#10;</xsl:text>
      <xsl:for-each select="./namespace::*">
       <xsl:value-of select="position()"/>
       <xsl:text>. namespace prefix = "</xsl:text>
       <xsl:value-of select="name(.)"/>
       <xsl:text>"&#10;   namespace URI    = "</xsl:text>
       <xsl:value-of select="."/>
       <xsl:text>"&#10;</xsl:text>
      </xsl:for-each>
      <xsl:text>&#10;</xsl:text>
     </xsl:template>
    </xsl:stylesheet>
    

    XSLT文档的输出

    Find and print all element names and namespace nodes
    
    name          = "root"
    namespace URI = ""
    This node has 2 namespace nodes:
    1. namespace prefix = "xml"
       namespace URI    = "http://www.w3.org/XML/1998/namespace"
    2. namespace prefix = "ns1"
       namespace URI    = "http://example.com/namespace-1"
    
    name          = "nothing"
    namespace URI = ""
    This node has 2 namespace nodes:
    1. namespace prefix = "xml"
       namespace URI    = "http://www.w3.org/XML/1998/namespace"
    2. namespace prefix = "ns1"
       namespace URI    = "http://example.com/namespace-1"
    
    name          = "default"
    namespace URI = "http://example.com/default"
    This node has 3 namespace nodes:
    1. namespace prefix = "xml"
       namespace URI    = "http://www.w3.org/XML/1998/namespace"
    2. namespace prefix = "ns1"
       namespace URI    = "http://example.com/namespace-1"
    3. namespace prefix = ""
       namespace URI    = "http://example.com/default"
    
    name          = "override"
    namespace URI = ""
    This node has 3 namespace nodes:
    1. namespace prefix = "xml"
       namespace URI    = "http://www.w3.org/XML/1998/namespace"
    2. namespace prefix = "ns1"
       namespace URI    = "http://example.com/namespace-1"
    3. namespace prefix = ""
       namespace URI    = ""
    
    name          = "ns1:namespace-1"
    namespace URI = "http://example.com/namespace-1"
    This node has 2 namespace nodes:
    1. namespace prefix = "xml"
       namespace URI    = "http://www.w3.org/XML/1998/namespace"
    2. namespace prefix = "ns1"
       namespace URI    = "http://example.com/namespace-1"
    
    name          = "ns1:attribute-1"
    namespace URI = "http://example.com/namespace-1"
    This node has 0 namespace nodes:
    
    name          = "attribute-2"
    namespace URI = ""
    This node has 0 namespace nodes:
    
    name          = "ns2:namespace-2"
    namespace URI = "http://example.com/namespace-2"
    This node has 3 namespace nodes:
    1. namespace prefix = "xml"
       namespace URI    = "http://www.w3.org/XML/1998/namespace"
    2. namespace prefix = "ns1"
       namespace URI    = "http://example.com/namespace-1"
    3. namespace prefix = "ns2"
       namespace URI    = "http://example.com/namespace-2"
    
    End of tests
    

    示例显示的一些内容:

    1. 所有元素都有一个xml名称空间的节点
    2. 元素rootnothing有一个前缀命名空间“namespace-1”的节点,即使这些元素不使用它
    3. 默认命名空间的名称为空,如default
    4. 所示
    5. 元素root没有默认命名空间的节点,但override有,即使它们都不属于命名空间。这是因为override有一个默认的名称空间声明,只有这种情况下它被重置为空。
    6. namespace-1具有与元素nothing类似的命名空间节点,尽管另一个是前缀并使用命名空间而另一个不是
    7. namespace-2是唯一拥有ns2前缀节点的元素,因为兄弟元素不在命名空间声明的范围内
    8. 有趣的是,属性可以属于命名空间,但它们似乎仍然没有任何命名空间节点。根据规范,命名空间节点也有扩展名,但URI始终为空。
    9. 比较名称空间时,请记住元素不共享名称空间节点。即使父和子拥有所有类似的命名空间节点,它们实际上也不是同一个节点。就像两个不同对象的变量不一样,即使它们具有相同的名称和相同的值。