4

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

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

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

有什么想法吗?

提前致谢 :)

4

5 回答 5

5

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

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

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

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

于 2009-12-11T08:48:31.233 回答
2

一个可移植的(XPath 1.0 和 2.0)解决方案是:

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

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

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

测试 - 找到所有<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>
于 2009-12-11T10:21:35.900 回答
1

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

<xsl:if test="ancestor::*[. is $somenode]">

编辑:我和你一起学习。看看这是否有效(我希望我的 XSL 调试器可以在这个系统上使用 :-)

于 2009-12-11T06:24:18.800 回答
1

答案很简单,

你所要做的就是:

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

    ...然后添加其余的

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

于 2011-11-15T17:50:25.917 回答
0

后代检查

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

如果您有一段看起来像这样的 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比较运算符,因为它需要叶节点,而叶节点没有后代。

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

于 2009-12-11T07:12:15.460 回答