Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSL(T) current/previous/next

Tags:

xslt

I know there is the current() function to retrieve the current node in XSL, but is there a way to be able to reference the "previous" and "next" nodes in reference to the current position?

like image 225
James Avatar asked Jul 17 '26 23:07

James


1 Answers

No. The current context cannot know which nodes are "next" or "previous".

This is because when, for example, templates are applied, the mechanics go like this:

  1. You do: <xsl:apply-templates select="*" /><!-- select 3 nodes (a,b,c) -->
  2. The XSLT processor makes list of nodes to be processed (a,b,c)
  3. For each of those nodes, the XSLT processor selects and executes a matching template
  4. When the template is called, the current() node is defined, and position() is defined, but other than that the template has no knowledge of the execution flow.
  5. Execution order is subject to the processors preferences, as long as the outcome is guaranteed to be the same. Your (theoretical) predictions might be true for one processor, and wrong for another. For a side-effects free programming language like XSLT, knowledge like this would be a dangerous thing, I think (because people would start to rely on execution order).

You can do use the following::sibling or preceding::sibling XPath axes, but that's something different from knowing what node will be processed next

EDIT

The above explanation tries to answer the question as it has been asked, but the OP meant something different. It's about grouping/outputting unique nodes only.

As per the OP's request, here a quick demonstration of how to achieve a grouping using the XPath axes.

XML (the items are pre-sorted):

<items>
  <item type="a"></item>
  <item type="a"></item>
  <item type="a"></item>
  <item type="a"></item>
  <item type="b"></item>
  <item type="e"></item>
</items>

XSLT

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

  <xsl:template match="/items">
    <!-- copy the root element -->
    <xsl:copy>
      <!-- select those items that differ from any of their predecessors -->
      <xsl:apply-templates select="
        item[
          not(@type = preceding-sibling::item/@type)
        ]
      " />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="item">
    <!-- copy the item to the output -->
    <xsl:copy-of select="." />
  </xsl:template>

</xsl:stylesheet>

Output:

<items>
  <item type="a"></item>
  <item type="b"></item>
  <item type="e"></item>
</items>
like image 156
Tomalak Avatar answered Jul 22 '26 12:07

Tomalak



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!