如何使用命名空间从XML中进行“选择”?

15

我有一个类似以下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>

不匹配。我移除了所有的命名空间,它就可以正常工作了。那么,我该如何让“select”与“Row”匹配呢?

3个回答

35

为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>

11

如果您不关心命名空间,可以使用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>

1
这个QName测试 *:local-name 仅在XSLT/XPath 2.0中有效。 - user357812
这个解决方案有点不太干净,但是很有效。它也解决了我的问题(尝试选择一个滑动的命名空间子节点)。 - Kevin Teljeur
@Kevin 哪一部分?第一部分还是第二部分? - Tomalak
1
当命名空间URI不固定时,这样做是完全可以的。如果您只有一些可能的URI,您也可以注册它们并编写 <xsl:for-each select="ns1:foo|ns2:foo|ns3:foo"> - Tomalak
1
那是一个默认的命名空间声明。XPath 的默认命名空间概念在 XSLT 1.0 中不存在。只需在您的 XSLT 文件中注册 xmlns:xhtml="http://www.w3.org/1999/xhtml" 并使用前缀,如 select="xhtml:body" - Tomalak
显示剩余3条评论

7

Tomalekckarras给出了不错的答案,但我想澄清其中的原因。

你没有匹配到的元素在文档中存在的范围的默认命名空间中,也就是说,在其声明的命名空间中没有前缀(例如:

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

在工作簿元素上(即Workbook元素),尽管标签名缺少命名空间前缀,但它们处于一个命名空间中。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接