Xslt 所有X元素都在Y之下,但在另一个X元素之前,是Y的后代
[编辑以消除肖恩注意到的歧义。-谢谢] 当当前元素为时,我需要一个XPATH表达式,该表达式返回红色和绿色元素,而不是蓝色和黄色元素,正如规范所做的那样 当前元素为时,同一表达式需要返回蓝色元素;当,黄色元素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"> . . . . . .
类似于//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>
===================================