XSLT,找出最后一个子节点是否是特定元素

时间:2010-10-03 22:17:19

标签: xslt xpath

请看以下两个例子:

<foo>some text <bar/> and maybe some more</foo>

<foo>some text <bar/> and a last <bar/></foo>

bar元素中的混合文本节点和foo元素。现在我在foo,想知道最后一个孩子是bar。第一个例子应该被证明是错误的,因为bar之后有文本,但第二个例子应该是真的。

如何使用XSLT实现此目的?

3 个答案:

答案 0 :(得分:13)

只需选择<foo>元素的最后一个节点,然后使用self轴来解析节点类型。

/foo/node()[position()=last()]/self::bar

如果最后一个节点不是元素,则此XPath表达式返回一个空集(等同于布尔值false)。如果要专门获取值truefalse,请将此表达式包装在XPath函数boolean()中。使用self::*代替self::bar来匹配任何元素作为最后一个节点。

输入XML文档:

<root>
    <foo>some text <bar/> and maybe some more</foo>
    <foo>some text <bar/> and a last <bar/></foo>
</root>

XSLT文档示例:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text"/>

<xsl:template match="foo">
    <xsl:choose>
        <xsl:when test="node()[position()=last()]/self::bar">
            <xsl:text>bar element at the end&#10;</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text>text at the end&#10;</xsl:text>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

样式表的输出:

text at the end
bar element at the end

答案 1 :(得分:7)

  

现在我在foo,想找到   如果最后一个孩子是bar

使用

node()[last()][self::bar]

任何非空节点集的布尔值为true(),否则为false()。您可以直接使用上述表达式(未修改)作为任何test<xsl:if>的{​​{1}}属性的值。

更好,使用

<xsl:when>

作为foo/node()[last()][self::bar] 的{​​{1}}属性 - 因此您以纯粹的“推送”风格书写。

答案 2 :(得分:5)

更新: 此答案解决了原始问题标题中所述的要求,“查明最后一个子节点是否为文本节点”。但问题机构提出了不同的要求,而后者的要求似乎是OP所要求的。

前两个答案明确地测试最后一个孩子是否是bar元素,而不是直接测试它是否是文本节点。如果foo仅包含 “混合文本节点和条形元素”永远不会有零个孩子,这是正确的。

但您可能想直接测试最后一个孩子是否是文本节点:

  1. 有关样式表逻辑的可读性
  2. 如果元素包含除元素和文本之外的其他子元素:例如评论或处理说明
  3. 如果元素没有孩子
  4. 也许你知道后两种情况永远不会发生在你的情况下(但是从你的问题我猜想#3可以)。或者也许你是这么想但不确定,或者你没有想过它。无论哪种情况,直接测试你真正想知道的东西都更安全:

         test="node()[last()]/self::text()"
    

    因此,在@Dimitre的示例代码和输入的基础上,使用以下XML输入:

    <root>
       <foo>some text <bar/> and maybe some more</foo>
       <foo>some text <bar/> and a pi: <?foopi param=yes?></foo>
       <foo>some text <bar/> and a comment: <!-- baz --></foo>
       <foo>some text and an element: <bar /></foo>
       <foo noChildren="true" />
    </root>
    

    使用此XSLT模板:

       <xsl:template match="foo">
          <xsl:choose>
             <xsl:when test="node()[last()]/self::text()">
                <xsl:text>text at the end;&#10;</xsl:text>
             </xsl:when>
             <xsl:when test="node()[last()]/self::*">
                <xsl:text>element at the end;&#10;</xsl:text>
             </xsl:when>
             <xsl:otherwise>
                <xsl:text>neither text nor element child at the end;&#10;</xsl:text>
             </xsl:otherwise>
          </xsl:choose>
       </xsl:template>
    

    的产率:

       text at the end;
       neither text nor element child at the end;
       neither text nor element child at the end;
       element at the end;
       neither text nor element child at the end;