首页 > 解决方案 > 如何检查节点的至少一个后代是否具有文本内容?

问题描述

我有一个看起来像的 XML

<xml>
    <grandparent>
        <parent>
            <child1/>
            <child2/>
            <child3>value</child3>
        </parent>
    </grandparent>
</xml>

如果父母的至少一个后代具有价值,我需要应用某个模板

搜索这个网站后,我想出了一个代码

<xsl:if test="grandparent/parent//* != '' ">
    <xsl:apply-templates select="parent"/>
</xsl:if>

但它不起作用。当我运行它时没有任何反应。apply-template 本身确实有效,所以问题不在于模板我做错了什么?

标签: xslt

解决方案


如果父母的至少一个后代具有价值,我需要应用某个模板

搜索这个网站后,我想出了一个代码

<xsl:if test="grandparent/parent//* != '' ">
    <xsl:apply-templates select="template1"/>
</xsl:if>

但它不起作用。

分析

  1. 当使用<xsl:apply-templates>指令应用模板时,不能指定任何模板名称(并且模板通常没有命名)。该select属性应该包含一个 XPath 表达式,它返回一个节点集(XSLT 3.0 中的一个序列),其中包含必须应用模板的节点。
  2. 因此select="template1"意味着应用名为“template1”的模板,而是将模板应用到当前节点的任何子元素,名为template1由于template1在提供的 XML 文档中没有命名元素,因此没有选择任何内容,也没有应用模板。这解释了报告的行为

您可能想要使用<xsl:call-template name="template1">,但调用命名模板在 XSLT 中通常不是一个好的做法。

此外,您还没有指定应用或调用模板时的当前节点是什么。

解决方案

假设当前节点是 XML 文档中的顶部节点。

下面是一个仍然使用<xsl:apply-templates>但仅指定 XSLT 处理器在选择要执行的模板时使用的模板模式的转换:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="grandparent">
    <xsl:apply-templates mode="template1" select="parent[*//text()]"/>
  </xsl:template>

  <xsl:template match="parent" mode="template1">
    Template in mode template1 Applied
  </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<xml>
    <grandparent>
        <parent>
            <child1/>
            <child2/>
            <child3>value</child3>
        </parent>
    </grandparent>
</xml>

产生了想要的结果(显示模板被选择执行和执行):

Template in mode template1 Applied

现在让我们用一个修改过的 XML 文档来测试它,其中没有子grandparent/parent节点有文本节点子节点:

<xml>
    <grandparent>
        <parent>
            <child1/>
            <child2/>
            <child3></child3>
        </parent>
    </grandparent>
</xml>

当我们对这个 XML 文档应用相同的转换时,不会产生任何输出——完全符合我们的要求。


推荐阅读