XPath/XSLT嵌套谓词:如何获取外部谓词的上下文?

pen*_*tur 13 xslt xpath nested predicate

似乎这个问题之前没有在stackoverflow上讨论过,除了使用嵌套的XPath Predicates ...精炼在哪里提供了不涉及嵌套谓词的解决方案.

所以我试着写出我想要得到的过度简化的样本:

输入:

<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>
Run Code Online (Sandbox Code Playgroud)

输出:

<root>
    <hungryAnimals>
        <cage name="B"/>
        <cage name="D"/>
    </hungryAnimals>
</root>
Run Code Online (Sandbox Code Playgroud)

或者,如果没有交叉点,

<root>
    <everythingIsFine/>
</root>
Run Code Online (Sandbox Code Playgroud)

我想使用嵌套谓词来获取它:

<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>
Run Code Online (Sandbox Code Playgroud)

那么我该?????怎么写呢呢?

我知道我可以使用一个更多的模板和变量/参数的广泛使用来重写整个样式表,但它甚至使这个样式表变得更加复杂,更不用说真实问题的真实样式表了.

它在XPath引用中写入,点.符号表示当前上下文节点,但它没有告诉在此之前是否有可能获取上下文节点; 我无法相信XPath缺少这个明显的功能.

Dim*_*hev 10

XPath 2.0单线程:

for $a in /*/animalsDictionary/cage
      return
        if(/*/shortOfSupply/*[my:isA($a/@animal, @animal)])
          then $a
          else ()
Run Code Online (Sandbox Code Playgroud)

当应用于提供的XML文档时,选择:

   <cage name="B"/>
   <cage name="D"/>
Run Code Online (Sandbox Code Playgroud)

不能使用单个XPath 1.0表达式来发现给定的笼子包含饥饿的动物.

这是一个XSLT解决方案(XSLT 2.0仅用于避免使用扩展函数进行比较 - 在​​XSLT 1.0解决方案中,将使用扩展函数进行比较,并使用xxx:node-set()扩展来测试是否通过在模板中应用模板生成的RTF变量的主体包含任何子元素):

<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>
Run Code Online (Sandbox Code Playgroud)

当对提供的XML文档应用此转换时(已更正为格式正确):

<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>
Run Code Online (Sandbox Code Playgroud)

产生了想要的正确结果:

<root>
   <hungryAnimals>
      <cage name="B"/>
      <cage name="D"/>
   </hungryAnimals>
</root>
Run Code Online (Sandbox Code Playgroud)

说明:请注意使用XSLT current()函数.