1
<div n="a">
  . . . 
    . . .
      <spec>red</spec>
      <div n="d">
          . . . 
      </div>
      <spec>green</spec>
      . . .
         <div n="b">
            . . .
              <spec>blue</spec>
            . . .
         </div>
         <div n="c">
           <spec>yellow</spec>
         </div>
      . . .
    . . .
  . . .
</div>

[编辑以消除肖恩注意到的歧义。 - 谢谢]

当当前元素为<div n="a">时,我需要一个 XPATH 表达式,它返回红色和绿色元素,但不返回蓝色和黄色元素,就像.//spec这样。

当前元素为<div n="b">时,同样的表达式需要返回蓝色元素;时<div n="c">,黄色元素。

就像是.//spec[but no deeper than another div if there is one]

4

2 回答 2

3

在 XSLT 1.0 中,假设当前节点是 a div

.//spec[generate-id(current())=generate-id(ancestor::div[1])]

在相同假设下的 XSLT 2.0 中

.//spec[ancestor::div[1] is current()]

还有一个纯 XPath 2.0 表达式

for $this in .
     return
        $this//spec[ancestor::div[1] is $this]

完整的 XSLT 1.0 转换

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="div">
  <div n="{@n}"/>
  <xsl:copy-of select=
   ".//spec[generate-id(current())=generate-id(ancestor::div[1])]"/>
==============
  <xsl:apply-templates/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

应用于提供的 XML 文档时

<div n="a">
  . . .
    . . .
      <spec>red</spec>
      <spec>green</spec>
      . . .
         <div n="b">
            . . .
              <spec>blue</spec>
            . . .
         </div>
         <div n="c">
           <spec>yellow</spec>
         </div>
      . . .
    . . .
  . . .
</div>

产生了想要的正确结果

<div n="a"/>
<spec>red</spec>
<spec>green</spec>
==============
  <div n="b"/>
<spec>blue</spec>
==============
  <div n="c"/>
<spec>yellow</spec>
==============

完整的 XSLT 2.0 转换

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="div">

  <div n="{@n}"/>
  <xsl:sequence select=".//spec[ancestor::div[1] is current()]"/>
===================================
  <xsl:apply-templates/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

当应用于同一个 XML 文档(上图)时,会产生相同的正确结果:

<div n="a"/>
<spec>red</spec>
<spec>green</spec>
===================================
  <div n="b"/>
<spec>blue</spec>
===================================
  <div n="c"/>
<spec>yellow</spec>
===================================

并使用纯 XPath 2.0(否current()):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="div">

  <div n="{@n}"/>
  <xsl:sequence select="
    for $this in .
     return
        $this//spec[ancestor::div[1] is $this]"/>
===================================
  <xsl:apply-templates/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

产生相同的正确结果

<div n="a"/>
<spec>red</spec>
<spec>green</spec>
===================================
  <div n="b"/>
<spec>blue</spec>
===================================
  <div n="c"/>
<spec>yellow</spec>
===================================
于 2012-10-15T03:05:12.437 回答
1

假设您使用的是 XSLT 1.0,并且您想要选择“spec”子节点、所有子节点,然后将所需的“当前”节点作为 XSLT 焦点节点,设置以下变量...

<xsl:variable name="divs" select="*//div" />

现在,您可以使用此 XPath 表达式选择所有spec后代之前没有后代的所有后代div...

//spec[not((preceding::div|ancestor::div)[count(. | $divs) = count($divs)])]

警告

这应该可以,但我还没有测试过。带着这种谨慎,我把它作为一个练习留给 OP 来测试。

笔记

如果您真的非常想要一个不需要您声明附加变量的 XPath 表达式,并且很幸运已经将当前节点保存在节点集中(我们称之为 $ref),您可以使用这个相当低效的 XPath 表达式...

$ref//spec[not((preceding::div|ancestor::div)[count(. | $ref/*//div) =
                                              count(    $ref/*//div)  ])]

附录

这是一个测试用例,我可能指的是评论流。

测试用例 1 输入:

<div n="a">
      <spec>red</spec>
      <div n="x"/>
      <spec>green</spec>
      <div n="b">
        <spec>blue</spec>
      </div>
      <div n="c">
        <spec>yellow</spec>
      </div>
</div>

测试用例 1 预期输出:

  • 应该只是red
于 2012-10-15T03:05:10.923 回答