XSL - Как определить, является ли элемент последним в серии

У меня есть шаблон XSL, который выбран для выполнения (ниже). То, что я хотел бы сделать, это узнать, соответствует ли мне последний Unit.

  <xsl:template match="Unit[@DeviceType = 'Node']">
    <!-- Am I the last Unit in this section of xml? -->
    <div class="unitchild">
      Node: #<xsl:value-of select="@id"/>
    </div>
  </xsl:template>

Пример XML

<Unit DeviceType="QueueMonitor" Master="1" Status="alive" id="7">
    <arbitarytags />
    <Unit DeviceType="Node" Master="0" Status="alive" id="8"/>
    <Unit DeviceType="Node" Master="0" Status="alive" id="88"/>
</Unit>

Ответ 1

Если вы хотите проверить, является ли это последним элементом Unit на том же уровне (с одним и тем же родительским элементом), даже если есть произвольные теги до, после и между ними, это будет работать:

<xsl:if test="not(following-sibling::Unit)">

Однако, если вы применяете шаблоны для подмножества, последнее в документе может не быть в обрабатываемом наборе. Для этого вы можете проверить, есть ли position() = last()

<xsl:if test="position() = last()">

Ответ 2

Текущий выбранный ответ, как правило, неверен!

<xsl:if test="not(following-sibling::Unit)">

Это не будет работать с каким-либо XML-документом и любым <xsl:apply-templates>

Первоначальный вопрос касается последнего Unit, а не последнего брата! Какой последний выбранный блок зависит только от выражения в атрибуте select <xsl:apply-templates>, а не от физических свойств документа XML.

Способ сделать это:

<xsl:apply-templates select="SomeExpression"/>

, затем в шаблоне, который соответствует узлам, выбранным SomeExpression:

<xsl:if test="position() = last()">
. . . . 
</xsl:if>

Это проверяет, является ли текущий node последним в node-list, выбранным <xsl:apply-templates>, а не то, что текущий node является последним sibling. Это отвечает именно на первоначальный вопрос.

Если вопрос был оформлен по-другому, спрашивая, как узнать, является ли последний sibling Unit текущим node, тогда лучшим решением было бы указать отдельный шаблон для этого последнего sibling node:

<xsl:template match="Unit[last()]">
    . . . . 
</xsl:template>

Обратите внимание на, что в этом случае нет необходимости писать какую-либо условную логику внутри шаблона, чтобы проверить, является ли текущий node "последним".

Ответ 3

Вы должны проверить позицию() = last(), но вы должны проверить ее в предикате, а не в теле шаблона:

<?xml version="1.0" encoding="utf-8"?>

<data>
    <item group="B">AAA</item>
    <item>BBB</item>
    <item group="B">CCC</item>
    <item>DDD</item>
    <item group="B">EEE</item>
    <item>FFF</item>
</data>

    <?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="data">
    <xsl:apply-templates select="item[@group]"/>
</xsl:template>

<xsl:template match="item">
    ITEM
    <xsl:if test="position() = last()">
    LAST IN CONTEXT
    </xsl:if>
</xsl:template>

<xsl:template match="item[position() = last()]">
    LAST ITEM
</xsl:template>

Ответ 4

Вы можете проверить position() на last():

<xsl:template match="Unit[@DeviceType = 'Node']">
 <!-- Am I the last Unit in this section of xml? -->     
 <xsl:if test="position() = last()">
   <!-- Yes I am! -->
   Last Unit
 </xsl:if>

 <div class="unitchild">
  Node: #<xsl:value-of select="@id"/>
 </div>
</xsl:template>

См. статью w3schools на xsl:if.