似乎这个问题之前没有在stackoverflow上讨论过,除了Working With Nested XPath Predicates ... Refined之外,还提供了不涉及嵌套谓词的解决方案。
所以我试着写出我想要得到的过分简化的样本:
输入:
<root>
<shortOfSupply>
<food animal="doggie"/>
<food animal="horse"/>
</shortOfSupply>
<animalsDictionary>
<cage name="A" animal="kittie"/>
<cage name="B" animal="dog"/>
<cage name="C" animal="cow"/>
<cage name="D" animal="zebra"/>
</animals>
</root>
输出:
<root>
<hungryAnimals>
<cage name="B"/>
<cage name="D"/>
</hungryAnimals>
</root>
或者,如果没有交叉点,
<root>
<everythingIsFine/>
</root>
我希望使用嵌套谓词来获取它:
<xsl:template match="cage">
<cage>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
</cage>
</xsl:template>
<xsl:template match="/root/animalsDictionary">
<xsl:choose>
<!-- in <food> in <cage> -->
<xsl:when test="cage[/root/shortOfSupply/food[ext:isEqualAnimals(./@animal, ?????/@animal)]]">
<hungryAnimals>
<xsl:apply-templates select="cage[/root/shortOfSupply/food[ext:isEqualAnimals(@animal, ?????/@animal)]]"/>
</hungryAnimals>
</xsl:when>
<xsl:otherwise>
<everythingIsFine/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
那我该怎么写呢?????
?
我知道我可以使用一个模板和变量/参数的大量使用来重写整个样式表,但它甚至使这个样式表变得更加复杂,更不用说真实问题的真实样式表了。
在XPath参考中写道,点.
符号表示当前上下文节点,但它没有告诉在此之前是否有可能获取上下文节点;我无法相信XPath缺少这个明显的功能。
答案 0 :(得分:10)
XPath 2.0 one-liner :
for $a in /*/animalsDictionary/cage
return
if(/*/shortOfSupply/*[my:isA($a/@animal, @animal)])
then $a
else ()
当应用于提供的XML文档时,选择:
<cage name="B"/>
<cage name="D"/>
不能使用单个XPath 1.0表达式来查找给定的笼子包含饥饿的动物。
这是一个XSLT解决方案(XSLT 2.0仅用于避免使用扩展函数进行比较 - 在XSLT 1.0解决方案中,将使用扩展函数进行比较和{{ 1}}扩展来测试通过在变量体中应用模板生成的RTF是否包含任何子元素):
xxx:node-set()
将此转换应用于提供的XML文档(更正为格式良好):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my:my" exclude-result-prefixes="xs my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<my:Dict>
<a genName="doggie">
<name>dog</name>
<name>bulldog</name>
<name>puppy</name>
</a>
<a genName="horse">
<name>horse</name>
<name>zebra</name>
<name>pony</name>
</a>
<a genName="cat">
<name>kittie</name>
<name>kitten</name>
</a>
</my:Dict>
<xsl:variable name="vDict" select=
"document('')/*/my:Dict/a"/>
<xsl:template match="/">
<root>
<xsl:variable name="vhungryCages">
<xsl:apply-templates select=
"/*/animalsDictionary/cage"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$vhungryCages/*">
<hungryAnimals>
<xsl:copy-of select="$vhungryCages"/>
</hungryAnimals>
</xsl:when>
<xsl:otherwise>
<everythingIsFine/>
</xsl:otherwise>
</xsl:choose>
</root>
</xsl:template>
<xsl:template match="cage">
<xsl:if test="
/*/shortOfSupply/*[my:isA(current()/@animal,@animal)]">
<cage name="{@name}"/>
</xsl:if>
</xsl:template>
<xsl:function name="my:isA" as="xs:boolean">
<xsl:param name="pSpecName" as="xs:string"/>
<xsl:param name="pGenName" as="xs:string"/>
<xsl:sequence select=
"$pSpecName = $vDict[@genName = $pGenName]/name"/>
</xsl:function>
</xsl:stylesheet>
产生了想要的正确结果:
<root>
<shortOfSupply>
<food animal="doggie"/>
<food animal="horse"/>
</shortOfSupply>
<animalsDictionary>
<cage name="A" animal="kittie"/>
<cage name="B" animal="dogs"/>
<cage name="C" animal="cow"/>
<cage name="D" animal="zebras"/>
</animalsDictionary>
</root>
解释:请注意使用XSLT <root>
<hungryAnimals>
<cage name="B"/>
<cage name="D"/>
</hungryAnimals>
</root>
函数。
答案 1 :(得分:4)
XPath 1.0不是“关系完整” - 它不能进行任意连接。如果你在XSLT中,你总是可以通过将变量绑定到中间节点集来解决限制,或者(有时)使用current()函数。
XPath 2.0引入了范围变量,这使它在关系上完整,因此这种限制已经消失。
答案 2 :(得分:0)
<xsl:when test="cage[@animal = /root/shortOfSupply/food/@animal]">
不足以表达您的测试条件吗?
答案 3 :(得分:0)
注意 XPath 中的点运算符与当前上下文相关。在 XSLT 中,当前模板上下文 _由函数current()
提供,其中大部分时间(并非总是)与.
。
您可以使用父轴缩写(../
)执行测试(以及应用模板):
cage[@animal=../../shortOfSupply/food/@animal]
此外,第一个模板中的匹配模式是错误的,它应该是相对于根:
/root/animalsDictionary
@Martin建议也显然是正确的。
您的最终模板略有修改:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="root/animalsDictionary">
<xsl:choose>
<xsl:when test="cage[@animal=../../shortOfSupply/food/@animal]">
<hungryAnimals>
<xsl:apply-templates select="cage[@animal
=../../shortOfSupply/food/@animal]"/>
</hungryAnimals>
</xsl:when>
<xsl:otherwise>
<everythingIsFine/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="cage">
<cage name="{@name}"/>
</xsl:template>
</xsl:stylesheet>