PDM
PDM

Reputation: 27

XSLT 2.0 previous value in a for-each-group

Given this kind of structure:

<ROOT>
    <MYROW>
        <CATEGORYNAME>first</CATEGORYNAME>
        <DATA>10</DATA>
    </MYROW>
    <MYROW>
        <CATEGORYNAME>second</CATEGORYNAME>
        <DATA>20</DATA>
    </MYROW>
    <MYROW>
        <CATEGORYNAME>second</CATEGORYNAME>
        <DATA>30</DATA>
    </MYROW>
    <MYROW>
        <CATEGORYNAME>first</CATEGORYNAME>
        <DATA>100</DATA>
    </MYROW>
</ROOT>

I am doing this kind of transformation:

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

    <xsl:output indent="yes"/>

    <xsl:template match="ROOT">
        <Worksheet>
            <xsl:for-each-group select="MYROW" group-by="CATEGORYNAME">
                <ROW>
                    <CELL>
                        <DATA>
                            <xsl:value-of select="current-grouping-key()"/>
                        </DATA>
                    </CELL>
                </ROW>
                <xsl:apply-templates select="current-group()"/>
            </xsl:for-each-group>
        </Worksheet>
    </xsl:template>

    <xsl:template match="MYROW">
        <ROW>
            <CELL>
                <xsl:value-of select="DATA"/>
            </CELL>
        </ROW>
    </xsl:template>
</xsl:transform>

I would like to compare the "DATA" value with its previous one in the group. I can't manage to get the previous value. I tried:

<xsl:value-of select="preceding-sibling::node()/DATA"/>

which gives all the previous sibling nodes in the original XML and not just in the current group by.

Basically I want to know if there is a way to use xpath within a group-by sequence.

Expected output:

<Worksheet>
   <ROW>
      <CELL>
         <DATA>first</DATA>
      </CELL>
   </ROW>
   <ROW>
      <CELL>
         <DATA color = "black">10</DATA>
      </CELL>
   </ROW>
   <ROW>
      <CELL>
         <DATA color = "blue">100</DATA>
      </CELL>
   </ROW>
   <ROW>
      <CELL>
         <DATA color = "red">5</DATA>
      </CELL>
   </ROW>
   <ROW>
      <CELL>
         <DATA>second</DATA>
      </CELL>
   </ROW>
   <ROW>
      <CELL>
         <DATA color = "black">20</DATA>
      </CELL>
   </ROW>
   <ROW>
      <CELL>
         <DATA color = "blue">30</DATA>
      </CELL>
   </ROW>
</Worksheet>

Upvotes: 0

Views: 1993

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167581

Assuming you have the <xsl:apply-templates select="current-group()"/> as shown and then a template for the <xsl:template match="MYROW"> then you can use

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
   xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">

    <xsl:output indent="yes"/>

    <xsl:template match="ROOT">
        <Worksheet>
            <xsl:for-each-group select="MYROW" group-by="CATEGORYNAME">
                <ROW>
                    <CELL>
                        <DATA>
                            <xsl:value-of select="current-grouping-key()"/>
                        </DATA>
                    </CELL>
                </ROW>
                <xsl:apply-templates select="current-group()"/>
            </xsl:for-each-group>
        </Worksheet>
    </xsl:template>

    <xsl:template match="MYROW">
        <xsl:variable name="pos" select="position()"/>                                                                      
        <xsl:variable name="preceding-group-member" select="current-group()[$pos - 1]"/>
        <xsl:variable name="this-data" select="xs:decimal(DATA)"/>
        <xsl:variable name="preceding-data" select="xs:decimal($preceding-group-member/DATA)"/>
        <ROW>
            <CELL color="{if ($pos eq 1 or $this-data eq $preceding-data) 
                         then 'black' else (if ($this-data gt $preceding-data) then 'blue' else 'red')}">
                <xsl:copy-of select="DATA"/>
            </CELL>
        </ROW>
    </xsl:template>
</xsl:transform>

Online at http://xsltransform.net/pPzifp8/1.

Upvotes: 1

Related Questions