如何从带有命名空间的 XML 中“选择”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/284094/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 12:12:26  来源:igfitidea点击:

How to 'select' from XML with namespaces?

xmlxslt

提问by Greg Ogle

I have an XML document something like :::

我有一个类似于 ::: 的 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>

The problem is when trying to select Rows with

问题是在尝试选择 Rows 时

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

It is not matching. I removed all of the name-spacing and it works fine. So, how do I get the 'select' to match Row?

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

回答by ckarras

Declare a namespace prefix for the namespace in your XSLT and then selectusing that prefix:

在 XSLT 中为命名空间声明命名空间前缀,然后select使用该前缀:

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

This usually results in XPaths that are easy to read. However, XSLT/XPath tools generate the following, equivalent code:

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

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

回答by Tomalak

If you don't care about the namespace, you can use the XPath `local-name()' function:

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

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

Alternatively the same same thing can be expressed like this. I'm not certain if this is standard XPath and if all XPath implementations support it (ColdFusion does, so probably Java does as well). Maybe someone knows if this conforms to any standard.

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

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

回答by ChuckB

Tomalekand ckarrasgive good answers, but I want to clarify the reasons behind them.

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

The elements you aren't matching are in the default namespace of the scope in which they occur in the doc, that is, they are in the namespace declared for that scope without a prefix (e.g.

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

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

on the Workbookelement). Even though the tagnames lack a namespace prefix, they are in a namespace.

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

However, XPath requires that all names of elements in a namespace be qualified with a prefix, or that the namespace be specified explicitly with namespace-uri()in a predicate. Hence, you must either use the local-name()function in a predicate to match the element name (and use the namespace-uri()function as well if there is a danger of name collisions across namespaces), or you must declare each namespace in which you wish to match elements in XPaths with a prefix, and qualify the element names with their namespace prefixes in the XPath expressions.

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