Xslt 所有X元素都在Y之下,但在另一个X元素之前,是Y的后代

Xslt 所有X元素都在Y之下,但在另一个X元素之前,是Y的后代,xslt,xpath,xslt-2.0,xpath-2.0,Xslt,Xpath,Xslt 2.0,Xpath 2.0,[编辑以消除肖恩注意到的歧义。-谢谢] 当当前元素为时,我需要一个XPATH表达式,该表达式返回红色和绿色元素,而不是蓝色和黄色元素,正如规范所做的那样 当前元素为时,同一表达式需要返回蓝色元素;当,黄色元素 类似于//spec[但如果有另一个div,则不超过另一个div]假设您使用的是XSLT 1.0,并且希望选择“spec”子级、所有子级,然后将所需的“current”节点作为XSLT焦点节点,设置以下变量 <div n="a"> . . . . . .

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

当当前元素为时,我需要一个XPATH表达式,该表达式返回红色和绿色元素,而不是蓝色和黄色元素,正如规范所做的那样

当前元素为时,同一表达式需要返回蓝色元素;当,黄色元素


类似于//spec[但如果有另一个div,则不超过另一个div]

假设您使用的是XSLT 1.0,并且希望选择“spec”子级、所有子级,然后将所需的“current”节点作为XSLT焦点节点,设置以下变量

<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>
警告 这应该是可行的,但我还没有测试过。有了这个警告,我把它作为一个练习留给OP来测试

笔记 如果您确实非常想要一个不需要声明额外变量的XPath表达式,并且您碰巧已经在节点集中保存了当前节点(我们称之为$ref),那么您可以使用这个效率相当低的XPath表达式

<xsl:variable name="divs" select="*//div" />
//spec[not((preceding::div|ancestor::div)[count(. | $divs) = count($divs)])]
补遗 这里是一个测试用例,我可能指的是注释流

测试用例1输入:

$ref//spec[not((preceding::div|ancestor::div)[count(. | $ref/*//div) =
                                              count(    $ref/*//div)  ])]
测试用例1预期输出:

应该是红色的
假设您使用的是XSLT 1.0,并且希望选择“spec”子级、所有子级,然后使用所需的“current”节点作为XSLT焦点节点,设置以下变量

<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>
警告 这应该是可行的,但我还没有测试过。有了这个警告,我把它作为一个练习留给OP来测试

笔记 如果您确实非常想要一个不需要声明额外变量的XPath表达式,并且您碰巧已经在节点集中保存了当前节点(我们称之为$ref),那么您可以使用这个效率相当低的XPath表达式

<xsl:variable name="divs" select="*//div" />
//spec[not((preceding::div|ancestor::div)[count(. | $divs) = count($divs)])]
补遗 这里是一个测试用例,我可能指的是注释流

测试用例1输入:

$ref//spec[not((preceding::div|ancestor::div)[count(. | $ref/*//div) =
                                              count(    $ref/*//div)  ])]
测试用例1预期输出:

应该是红色的 在XSLT 1.0中,假设当前节点是div:

在XSLT 2.0中,在相同的假设下:

以及一个纯XPath 2.0表达式:

完整XSLT 1.0转换:

产生相同的正确结果:

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

在XSLT 2.0中,在相同的假设下:

以及一个纯XPath 2.0表达式:

完整XSLT 1.0转换:

产生相同的正确结果:


哦,迪米特里,我喜欢。是的,当前节点将是一个div。和当前是同一个节点。好好利用电流!为什么需要生成id?@JPM,在XSLT 1.0中,生成id通常比计数更有效。|$ns2=1。另外,请务必在更新的答案中看到纯XPath 2.0表达式。为什么不只是current=祖先::div[1]?@Dimitre,我不确定您的XSLT 1.0解决方案是否正确。您能看看它是如何应用于测试用例1的吗?正如我在附录中所包含的那样?Sean说得对,我没有完全弄清楚。迪米特里说得对。我已经相应地编辑了Q。哦,迪米特里,我喜欢这样。是的,当前节点将是一个div。和当前是同一个节点。好好利用电流!为什么需要生成id?@JPM,在XSLT 1.0中,生成id通常比计数更有效。|$ns2=1。另外,请务必在更新的答案中看到纯XPath 2.0表达式。为什么不只是current=祖先::div[1]?@Dimitre,我不确定您的XSLT 1.0解决方案是否正确。您能看看它是如何应用于测试用例1的吗?正如我在附录中所包含的那样?Sean说得对,我没有完全弄清楚。迪米特里说得对。我已经相应地编辑了Q.SeanB.Durkin,OP显然使用了“后代”一词,而不是“兄弟姐妹”。因此,您的测试用例1与这个问题无关,因为其中一个div元素是自动关闭的,并且没有任何spec后代。SeanB.Durkin,OP显然使用了术语“后代”,而不是兄弟。因此,您的测试用例1与这个问题无关,因为其中一个div元素是自动关闭的,并且没有任何spec子体。
<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>
<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>
==============
<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>
<div n="a"/>
<spec>red</spec>
<spec>green</spec>
===================================
  <div n="b"/>
<spec>blue</spec>
===================================
  <div n="c"/>
<spec>yellow</spec>
===================================
<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>
===================================