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

发布于 2024-08-15 06:16:39 字数 295 浏览 3 评论 0原文

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

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

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

有人有什么想法吗?

提前致谢 :)

I'm pretty new to XSLT, but need to use it for a CMS using at the moment. I've already come up with a problem, but I'll try to describe my it without going into too much information about the underlying CMS. If you need more context to help me, I can add it in.

So all I want to do is test if a node of my xml is a descendant of a particular node.

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

Any ideas anyone?

Thanks in advance :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

も星光 2024-08-22 06:16:39

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

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

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

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

You should use union operation and node-set size comparison:

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

If $someNode is an ancestor of $currentNode, $someNode|$currentNode/ancestor::* will return the same node-set as $currentNode/ancestor::* (node-set don't have any doublons).

If not, the first node-set will have one more node than the second because of the union.

初与友歌 2024-08-22 06:16:39

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

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

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

非空节点集的计算结果为 true,因此满足条件。

测试 - 查找所有 的后代:

<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>

A portable (XPath 1.0 and 2.0) solution would be:

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

This walks up the ancestor axis and checks every element in it. If (and only if) the unique ID of one of the ancestors matches the unique ID of $someNode, the resulting node-set is not empty.

Non-empty node-sets evaluate to true, so the condition is fulfilled.

Test - find all <baz> that are descendant of <foo>:

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

and

<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>

results in

<baz>Test 1</baz>

Note that if you are referring to the actual current node, like I do in the for-each, there is no need for a separate $currentNode variable. All XPath is relative to the current node by default.

A variant would be the top-down way. It is less efficient though (probably by several orders of magnitude):

<xsl:if test="
  $someNode[//*[generate-id() = generate-id($currentNode)]]
">
Write this out.
</xsl:if>
树深时见影 2024-08-22 06:16:39

答案很简单,

您所要做的就是:

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

    ...然后添加其余的

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

The answer is quite easy,

all you have to do is:

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

    ... then add the rest

the logic is that if the node is a descendant of somenode, then it will have one or more of that node.

剑心龙吟 2024-08-22 06:16:39

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

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

编辑:我正在与您一起学习。看看这是否有效(我希望我的 XSL 调试器在此系统上可用:-)

Look at the "ancestor" axis in your XSL/XPath reference

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

EDIT: I'm learning along with you. See if this works (I wish I had my XSL debugger available on this system :-)

慕烟庭风 2024-08-22 06:16:39

后代检查

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

如果您有一段如下所示的 XML,并且想要匹配第一个 节点的后代 节点。

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]">

IMO 比较运算符在比较祖先时不能使用,因为它需要叶节点,而叶节点没有后代。

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

Descendant checking

The best way would be to use the descendant::* axis.

If you have a piece of XML looking like this and want to match the descendant <a> nodes from the first <alpha> node.

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()]">

Ancestor checking

This would probably work in most cases.

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

Where

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

Or you can just use generate-id() if you have multiple nodes to compare against and need to make sure that it is a node match and not a name match.

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

The is comparison operator cannot IMO be used when comparing ancestors since it requires a leaf node, and leaf nodes do not have descendants.

But i'd recommend using the descendant::* axis since it's much more readable and flexible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文