XSL:如何测试当前节点是否是另一个节点的后代
我是XSLT的新手,但需要将其用于目前使用的CMS。我已经提出了一个问题,但我会尝试描述它,而不会涉及底层CMS的太多信息。如果你需要更多的上下文来帮助我,我可以添加它。XSL:如何测试当前节点是否是另一个节点的后代
所以我想要做的就是测试如果我的XML的节点是特定节点的后代。
<xsl:if test="$currentNode::IsADescendantOf($someNode)">
Write this out.
</xsl:if>
任何想法的人?
感谢提前:)
您应该使用UNION操作和节点集的大小比较:
<xsl:if test="count($someNode|$currentNode/ancestor::*) = count($currentNode/ancestor::*)">
Write this out.
</xsl:if>
如果$ someNode是$ currentNode的祖先,$ someNode | $ currentNode /祖先:: *将返回与$ currentNode/ancestor :: *相同的节点集(node-set没有任何双重)。
如果不是,由于联合,第一个节点集将比第二个节点集多一个节点。
查看 “祖先” 轴在XSL/XPath的参考
<xsl:if test="ancestor::*[. is $somenode]">
编辑:我跟你一起学习。看看这工作(我希望我有这个系统上可用我的XSL调试器:-)
@Jim Garrison:感谢您的快速回复。这似乎是合理的,但我得到这个错误: System.Xml.Xsl.XslLoadException:期望一个节点测试,找到'$'。 – 2009-12-11 06:28:07
你说得对,我的解决方案不完整。我没有使用XSL ref,但基本思想是您需要使用祖先轴来选择所有的祖先节点,然后根据节点相等性将其过滤为$ somenode。 – 2009-12-11 06:32:29
非常感谢。现在我得到“is-same-node()'是一个未知的XSLT函数”我会继续讨论它,但是让我知道你是否有任何其他想法。 – 2009-12-11 06:42:09
后代检查
,最好的办法是使用后代:: *轴。
如果您有一段XML看起来像这样并且想要匹配来自第一个<alpha>
节点的后代<a>
节点。
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)"/>
或者你也可以使用产生-ID()如果你有多个节点以比较,需要确保它是一个节点的匹配,而不是名称匹配。
<xsl:variable name="node" select="generate-id(//alpha[3])"/>
<xsl:if test="ancestor::*[generate-id(.) = $node]">
is
的比较操作者可以比较祖先时,因为它需要的叶节点不IMO被使用,并且叶节点没有后代。
但我建议使用descendant :: *轴,因为它更具可读性和灵活性。
一种便携式(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>
注意,如果你指的是实际 CURREN t节点,就像我在for-each中那样,不需要单独的$currentNode
变量。默认情况下,所有XPath都与当前节点相关。
变体将是自上而下的方式。这是低效率的,但(可能是由几个数量级):
<xsl:if test="
$someNode[//*[generate-id() = generate-id($currentNode)]]
">
Write this out.
</xsl:if>
答案很简单,
所有你需要做的是:
<xsl:if test="count(ancestor::somenode)>0">
.. 。然后添加其余的
的逻辑是,如果节点是somenode的后代,那么它将有一个或多个该节点。
@Erlock:非常感谢您的帮助。工作过一种享受。 – 2009-12-13 23:38:48