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

Joh*_*han 9 xslt xpath

请看以下两个例子:

<foo>some text <bar/> and maybe some more</foo>
Run Code Online (Sandbox Code Playgroud)

<foo>some text <bar/> and a last <bar/></foo>
Run Code Online (Sandbox Code Playgroud)

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

如何使用XSLT实现这一目标?

jas*_*sso 14

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

/foo/node()[position()=last()]/self::bar
Run Code Online (Sandbox Code Playgroud)

如果最后一个节点不是元素,则此XPath表达式返回一个空集(等同于布尔值false).如果要专门获取值,true或者false将此表达式包装在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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

样式表的输出:

text at the end
bar element at the end
Run Code Online (Sandbox Code Playgroud)


Dim*_*hev 7

现在我在foo,并想知道最后一个孩子是否是一个bar

用途:

node()[last()][self::bar]
Run Code Online (Sandbox Code Playgroud)

任何非空节点集的布尔值true()都是false(),否则就是.您可以直接使用上面的表达式(未修改)作为test任何<xsl:if>或的属性值<xsl:when>.

更好,使用:

foo/node()[last()][self::bar]
Run Code Online (Sandbox Code Playgroud)

作为一个match属性<xsl:template>- 因此你用纯粹的"推"式写作.


Lar*_*rsH 5

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

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

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

  1. 为了样式表逻辑的可读性
  2. 如果元素包含除元素和文本之外的其他子元素:例如注释或处理指令
  3. 如果元素没有子元素

也许你知道后两种情况永远不会发生在你的情况下(但是根据你的问题我会猜到#3可以).或者也许你是这么想但不确定,或者你没有想过它.在任何一种情况下,直接测试你真正想知道的东西更安全:

     test="node()[last()]/self::text()"
Run Code Online (Sandbox Code Playgroud)

因此,在@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>
Run Code Online (Sandbox Code Playgroud)

使用此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>
Run Code Online (Sandbox Code Playgroud)

收益率:

   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;
Run Code Online (Sandbox Code Playgroud)

  • 好的补充.但是先前的答案并没有像你的第一句话所暗示的那样改变OP的赎罪.从问题:"想知道最后一个孩子是否是一个酒吧". (2认同)