【问题标题】:How to 'select' from XML with namespaces?如何使用命名空间从 XML 中“选择”?
【发布时间】:2010-09-21 23:54:47
【问题描述】:

我有一个类似于 ::: 的 XML 文档

<?xml version="1.0" encoding="utf-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
          xmlns:o="urn:schemas-microsoft-com:office:office"
          xmlns:x="urn:schemas-microsoft-com:office:excel"
          xmlns="urn:schemas-microsoft-com:office:spreadsheet">
  <Worksheet ss:Name="Worksheet1">
    <Table>
      <Column ss:Width="100"></Column>

      <Row>
        <Cell ss:Index="1" ss:StyleID="headerStyle">
          <Data ss:Type="String">Submitted By</Data>
        </Cell>
      </Row>
      <Row>
        <Cell ss:Index="1" ss:StyleID="alternatingItemStyle">
          <Data ss:Type="String">Value1-0</Data>
        </Cell>
      </Row>
    </Table>
    <AutoFilter xmlns="urn:schemas-microsoft-com:office:excel"
                x:Range="R1C1:R1C5"></AutoFilter>
  </Worksheet>
</Workbook>

问题是在尝试使用

选择行时
  <xsl:for-each select="//Row">
    <xsl:copy-of select="."/>
  </xsl:for-each>

不匹配。我删除了所有的名称间距,它工作正常。那么,如何让“选择”匹配行?

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    为 XSLT 中的命名空间声明一个命名空间前缀,然后使用该前缀 select

    <xsl:stylesheet ... xmlns:os="urn:schemas-microsoft-com:office:spreadsheet">
      ...   
      <xsl:for-each select="//os:Row">
        ...
      </xsl:for-each>
      ...
    </xsl:stylesheet>
    

    这通常会产生易于阅读的 XPath。但是,XSLT/XPath 工具会生成以下等效代码:

    <xsl:for-each select="//*[local-name()='Row' = and namespace-uri()='urn:schemas-microsoft-com:office:spreadsheet']">
       ...
    </xsl:for-each>
    

    【讨论】:

      【解决方案2】:

      如果您不关心命名空间,可以使用 XPath `local-name()' 函数:

      <xsl:for-each select="//*[local-name() = 'Row']">
        <xsl:copy-of select="."/>
      </xsl:for-each>
      

      同样的事情也可以这样表达。我不确定这是否是标准 XPath 以及是否所有 XPath 实现都支持它(ColdFusion 支持,Java 也可能支持)。也许有人知道这是否符合任何标准。

      <xsl:for-each select="//:Row">
        <xsl:copy-of select="."/>
      </xsl:for-each>
      

      【讨论】:

      • 此 QName 测试 *:local-name 仅在 XSLT/XPath 2.0 中有效
      • 这个解决方案有点脏,但是很有效。它也解决了我的问题(试图选择一个光滑的命名空间子节点)。
      • @Kevin 是哪一部分?第一还是第二?
      • 当然。特别是如果命名空间 URI 不固定。如果你只有几个可能的 URI,你也可以注册所有这些并写 &lt;xsl:for-each select="ns1:foo|ns2:foo|ns3:foo"&gt;
      • 嗯,这是一个默认的命名空间声明。 XSLT 1.0 中不存在 XPath 的默认名称空间的概念。只需在 XSLT 文件中注册 xmlns:xhtml="http://www.w3.org/1999/xhtml" 并使用像 select="xhtml:body" 这样的前缀。
      【解决方案3】:

      Tomalekckarras 给出了很好的答案,但我想澄清他们背后的原因。

      您不匹配的元素位于它们在文档中出现的范围的默认命名空间中,也就是说,它们位于为该范围声明的没有前缀的命名空间中(例如

      xmlns="urn:schemas-microsoft-com:office:spreadsheet"
      

      Workbook 元素上)。即使标记名缺少命名空间前缀,它们也位于命名空间中。

      但是,XPath 要求命名空间中的所有元素名称都使用前缀进行限定,或者使用谓词中的namespace-uri() 显式指定命名空间。因此,您必须在谓词中使用local-name() 函数来匹配元素名称(如果存在跨名称空间名称冲突的危险,也必须使用namespace-uri() 函数),或者您必须声明您所在的每个名称空间希望用前缀匹配 XPath 中的元素,并用 XPath 表达式中的命名空间前缀限定元素名称。

      【讨论】:

        猜你喜欢
        • 2022-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-11
        • 1970-01-01
        • 2010-10-07
        • 2017-06-02
        • 2011-05-23
        相关资源
        最近更新 更多