XSL:如何测试当前节点是否是另一个节点的后代

时间:2009-12-11 06:17:03

标签: xml xslt descendant

我对XSLT很新,但现在需要将它用于CMS。我已经提出了一个问题,但我会尝试描述我的问题,而不会涉及有关底层CMS的太多信息。如果您需要更多上下文来帮助我,我可以添加它。

所以我想做的就是测试我的xml的节点是否是特定节点的后代。

<xsl:if test="$currentNode::IsADescendantOf($someNode)">
Write this out.
</xsl:if>

任何想法?

提前致谢:)

5 个答案:

答案 0 :(得分:5)

您应该使用union操作和节点集大小比较:

<xsl:if test="count($someNode|$currentNode/ancestor::*) = count($currentNode/ancestor::*)">
Write this out.
</xsl:if>

如果 $ someNode $ currentNode 的祖先,$ someNode | $ currentNode / ancestor :: *将返回与$ currentNode / ancestor相同的节点集: :*(节点集没有任何双重因素)。

如果没有,由于联合,第一个节点集将比第二个节点集多一个节点。

答案 1 :(得分:2)

便携式(XPath 1.0和2.0)解决方案将是:

<xsl:if test="
  $currentNode/ancestor::*[generate-id() = generate-id($someNode)]
">
Write this out.
</xsl:if>

这会走向祖先轴并检查其中的每个元素。如果(且仅当)其中一个祖先的唯一ID与唯一ID $someNode匹配,则结果节点集不为空。

非空节点集评估为true,因此满足条件。

测试 - 找到<baz>的后代的所有<foo>

<xml>
  <foo>
    <bar>
      <baz>Test 1</baz>
    </bar>
  </foo>
  <baz>Test 2</baz>
</xml>

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="/">
    <xsl:variable name="someNode" select="//foo[1]" />

    <!-- test each <baz> node if it has <foo> as a parent -->
    <xsl:for-each select="//baz">
      <xsl:if test="
        ancestor::*[generate-id() = generate-id($someNode)]
      ">
        <xsl:copy-of select="." />
      </xsl:if>

    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

结果

<baz>Test 1</baz>

请注意,如果您指的是实际当前节点,就像我在for-each中所做的那样,则不需要单独的$currentNode变量。默认情况下,所有XPath都相对于当前节点。

变体将是自上而下的方式。虽然效率较低(可能是几个数量级):

<xsl:if test="
  $someNode[//*[generate-id() = generate-id($currentNode)]]
">
Write this out.
</xsl:if>

答案 2 :(得分:1)

查看XSL / XPath参考中的“祖先”轴

<xsl:if test="ancestor::*[. is $somenode]">
编辑:我和你一起学习。看看这是否有效(我希望我的系统上有我的XSL调试器: - )

答案 3 :(得分:1)

答案很简单,

你所要做的就是:

<xsl:if test="count(ancestor::somenode)>0">

...然后添加其余的

逻辑是,如果节点是somenode的后代,那么它将具有该节点中的一个或多个。

答案 4 :(得分:0)

后裔检查

最好的方法是使用descendant :: * axis。

如果您有一段XML看起来像这样,并希望匹配来自第一个<a>节点的后代<alpha>节点。

XML

<root>
<!-- check for descendants of the following alpha node-->
<alpha>
  <!-- match the following node-->
  <a>...</a>
  <b>...</b>
  <c>...</c>
</alpha>
<alpha>
  <a>...</a>
  <c>...</c>
</alpha>
</root>

XSLT

<xsl:if test="/root/alpha[1]/descendant::a[. is current()]">

祖先检查

在大多数情况下,这可能会有效。

<xsl:if test="ancestor::*[name() = $node]">

其中

<xsl:variable name="node" select="name(//alpha)"/>

如果您有多个要比较的节点,并且需要确保它是节点匹配而不是名称匹配,您可以使用generate-id()。

<xsl:variable name="node" select="generate-id(//alpha[3])"/>
<xsl:if test="ancestor::*[generate-id(.) = $node]">

比较祖先时,is比较运算符不能被IMO使用,因为它需要一个叶子节点,并且叶子节点没有后代。

但我建议使用后代:: *轴,因为它更具可读性和灵活性。