Shadi
Shadi

Reputation: 557

using a counter for all groups members in for-each-group

I have a problem where I have an xml content with different keys needs to be grouped together and displayed, when displayed there is a pagination so I can't display all entries on the same page, I'm using for-each-group for grouping the items, and loop through each current-group() and display its item, the xml is something like this:

<entry>
    <key>key1</key>
    <value>value1</value>
</entry>

<entry>
    <key>key2</key>
    <value>value2</value>
</entry>

<entry>
    <key>key1</key>
    <value>value3</value>
</entry>
<entry>
    <key>key1</key>
    <value>value4</value>
</entry>
<entry>
    <key>key3</key>
    <value>value5</value>
</entry>
<entry>
    <key>key2</key>
    <value>value6</value>
</entry>
<entry>
    <key>key4</key>
    <value>value7</value>
</entry>
<entry>
    <key>key3</key>
    <value>value8</value>
</entry>
<entry>
    <key>key5</key>
    <value>value9</value>
</entry>
<entry>
    <key>key1</key>
    <value>value10</value>
</entry>
<entry>
    <key>key2</key>
    <value>value11</value>
</entry>

which should display like:

Page1:

key1
    value1
    value3
    value4
    value10

key2 
    value2
    value6
    value11
key3
    value5
    value8
key4
    value7

Page2:

 key5
    value9

the xsl I'm using without pagination is

<xsl:for-each-group select="entry" group-by="key">
    <xsl:value-of select="current-grouping-key()"/>
    <xsl:for-each select="current-grouping()">
           <xsl:apply-templates select="." />
      </xsl:for-each>
</xsl:for-each-group>

I need to display only 10 items on each page, how can I get the count of preceding entries of current-grouping()

edit for more info:

I have a variable $size and $offsite, what I'm basically trying to do is something like :

<xsl:if test="$count &gt; $offset and $count &lt;= $offset + $size">
    <xsl:apply-templates select="." />
</xsl:if>

where $count would have the count of all items already rendered, ideally if some how I can create a counter similar to position() in for-each but it doesn't restart with each loop of current-group().

if I don't want group items by key, I would have done something like this:

<xsl:for-each select="entry">
        <xsl:if test="position() &gt; $offset and position() &lt;= $offset + $size">
               <xsl:apply-templates select="." />
        </xsl:if>
</xsl:for-each>

but now since I'm using for-each-group, and the entries of each group are looped through individually, how can I keep track of entries that are already rendered from preceding groups.

Upvotes: 1

Views: 1055

Answers (1)

Ian Roberts
Ian Roberts

Reputation: 122364

You could do it in two stages - first re-order the whole unpaginated list of entries so they are grouped together by key (i.e. in the order that the final output requires), then take the appropriate page "slice" of that sequence to do the actual transformation:

<xsl:variable name="orderedEntries" as="element()*">
  <xsl:for-each-group select="entry" group-by="key">
    <xsl:sequence select="current-group()" />
  </xsl:for-each-group>
</xsl:variable>

<xsl:for-each-group select="$orderedEntries[
            position() &gt; $offset and position() &lt;= $offset + $size]"
     group-by="key">
  <xsl:value-of select="current-grouping-key()"/>
  <xsl:for-each select="current-group()">
    <xsl:apply-templates select="." />
  </xsl:for-each>
</xsl:for-each-group>

This will work even if the page break is part way through a group, e.g. an $offset and $size of 5 given your example input would produce

key2 
    value6
    value11
key3
    value5
    value8
key4
    value7

P.S. as Martin points out in a comment, the

  <xsl:for-each select="current-group()">
    <xsl:apply-templates select="." />
  </xsl:for-each>

is for most purposes equivalent to simply

  <xsl:apply-templates select="current-group()"/>

(the only difference being in the values of position() and last() that the called templates will see)

Upvotes: 2

Related Questions