<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]
答案 0 :(得分:3)
在XSLT 1.0中,假设当前节点是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>
===================================
答案 1 :(得分: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表达式, AND 你碰巧很幸运,你已经在节点集中保存了当前节点(让称之为$ 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