1

I am new to xsl. I understand that some similar questions have been asked, but I need help since I can't figure out what was wrong with my code. I have xml transactions file. I want to ,first, group by date, then sort each group of transactions by time

I have this xml

<History>
    <ShareLoanResults>
        <Account>123</Account>
        <PostingDt>20180718</PostingDt>
        <PostingTime>215642</PostingTime>
        <AmtLoan>000000000</AmtLoan>
        <AmtShare>000000001</AmtShare>
        <AmtInt>000000000</AmtInt>
        <Balance>000000487</Balance>
        <Description />
    </ShareLoanResults>
    <ShareLoanResults>
        <Account>123</Account>
        <PostingDt>20180719</PostingDt>
        <PostingTime>215650</PostingTime>
        <AmtLoan>000000000</AmtLoan>
        <AmtShare>000000003</AmtShare>
        <AmtInt>000000000</AmtInt>
        <Balance>000000494</Balance>
        <Description />
    </ShareLoanResults>
    <ShareLoanResults>
        <Account>123</Account>
        <PostingDt>20180719</PostingDt>
        <PostingTime>215640</PostingTime>
        <AmtLoan>000000000</AmtLoan>
        <AmtShare>000000002</AmtShare>
        <AmtInt>000000000</AmtInt>
        <Balance>000000489</Balance>
        <Description />
    </ShareLoanResults>
    <ShareLoanResults>
        <Account>123</Account>
        <PostingDt>20180717</PostingDt>
        <PostingTime>215641</PostingTime>
        <AmtLoan>000000000</AmtLoan>
        <AmtShare>000000004</AmtShare>
        <AmtInt>000000000</AmtInt>
        <Balance>000000486</Balance>
        <Description />
    </ShareLoanResults>
</History>

I am looking for this result

<History>
<ShareLoanResults>
    <Order>1</Order>
    <Account>123</Account>
    <PostingDt>20180717</PostingDt>
    <PostingTime>215641</PostingTime>
    <Amount>4</Amount>
</ShareLoanResults>
<ShareLoanResults>
    <Order>1</Order>
    <Account>123</Account>
    <PostingDt>20180718</PostingDt>
    <PostingTime>215642</PostingTime>
    <Amount>1</Amount>
</ShareLoanResults>
<ShareLoanResults>
    <Order>1</Order>
    <Account>123</Account>
    <PostingDt>20180719</PostingDt>
    <PostingTime>215640</PostingTime>
    <Amount>3</Amount>
</ShareLoanResults>
<ShareLoanResults>
    <Order>2</Order>
    <Account>123</Account>
    <PostingDt>20180719</PostingDt>
    <PostingTime>215650</PostingTime>
    <Amount>3</Amount>
</ShareLoanResults>
</History>

Here is my xsl

<xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method="xml" omit-xml-declaration="no" />

<xsl:template match="/">      
<xsl:copy>
    <xsl:for-each-group select="History/ShareLoanResults" group-by="PostingDt">
            <xsl:for-each select="current-group()">
            <xsl:sort select="PostingTime" order="ascending"/>
                <ShareLoanResults>
                    <Order>
                        <xsl:value-of select="position()"/>
                    </Order>
                    <Account>
                        <xsl:value-of select="Account"/>
                    </Account>
                    <PostingDt>
                        <xsl:value-of select="PostingDt"/>
                    </PostingDt>    
                    <PostingTime>
                        <xsl:value-of select="PostingTime"/>
                    </PostingTime>  
                    <Amount>
                        <xsl:value-of select="format-number(AmtShare,'#.000000')"/>
                    </Amount>
                </ShareLoanResults>
            </xsl:for-each>  
    </xsl:for-each-group>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

However, I am getting exception: javax.xml.transform.TransformerException: Could not find function: current-group

If I remove the <xsl:for-each-group select="current-group()"> and its corresponding closed tag, I get empty result below

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ShareLoanResults><Order/><Account/><PostingDt/><PostingTime/><Amount>NaN</Amount></ShareLoanResults>

Could someone please tell me what I did wrong and/or was missing? Thanks!

Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
Henry
  • 41
  • 4
  • 1
    Looks like you're trying to run an XSLT 2.0 stylesheet on an XSLT 1.0 processor. – michael.hor257k Nov 15 '18 at 18:27
  • 1
    See https://stackoverflow.com/a/25245033/317052 for a way to check what version your processor supports. If it only supports 1.0, you'll either need to change to a 2.0 processor or use [muenchian grouping](http://www.jenitennison.com/xslt/grouping/muenchian.html) in a 1.0 stylesheet. – Daniel Haley Nov 15 '18 at 18:29
  • 2
    I don't see any actual grouping done here. – michael.hor257k Nov 15 '18 at 18:33
  • 1
    Just noticed the same thing @michael.hor257k. This seems like just a sorting issue. – Daniel Haley Nov 15 '18 at 18:34
  • @DanielHaley Well, there *is* a running number within each group. – michael.hor257k Nov 15 '18 at 18:36
  • Thank you all! I am leaning towards to the issue of running XSLT 2.0 on 1.0 processor. I will follow Daniel suggestion to work on processor. PS: yes, there is a grouping by date first then sorting within that date. – Henry Nov 15 '18 at 19:27
  • As checked, Apache Software Foundation1 Does anyone know how to upgrade the processor to 2.0? Thanks! – Henry Nov 15 '18 at 19:45

1 Answers1

1

As mentioned by our XSLT gurus, you do not need any grouping or even a 2.0 processor. Simply sort by date and time, and have Order node count following siblings with same date:

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="/History">   
      <xsl:copy>   
        <xsl:apply-templates select="ShareLoanResults">
            <xsl:sort select="PostingDt"/>
            <xsl:sort select="PostingTime"/>
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="ShareLoanResults">      
        <xsl:variable name="curr_dt" select="PostingDt"/>
        <xsl:copy>
            <Order>
                <xsl:value-of select="count(following-sibling::*[PostingDt=$curr_dt])+1"/>
            </Order>
            <Account>
                <xsl:value-of select="Account"/>
            </Account>
            <PostingDt>
                <xsl:value-of select="PostingDt"/>
            </PostingDt>    
            <PostingTime>
                <xsl:value-of select="PostingTime"/>
            </PostingTime>  
            <Amount>
                <xsl:value-of select="format-number(AmtShare,'#.000000')"/>
            </Amount>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

XSLT Demo

Parfait
  • 104,375
  • 17
  • 94
  • 125
  • Thank you Parfait!!! According to https://xsltfiddle.liberty-development.net, your solution is correct. However, when I try to to use it in java xsl transformer, it gives me the exception "Can't have more than one root on a DOM!". By chance, do you know what the cause is? Thanks!!! – Henry Nov 15 '18 at 20:56
  • 1
    @Henry, change the template for `History` to wrap the `xsl:apply-templates` into an `xsl:copy`, as done in https://xsltfiddle.liberty-development.net/nc4NzRp/10, that way you get a result with a single `History` root element containing those `ShareLoanResults` elements. Or make sure on the Java side you use a DOMResult over a document fragment node, not a document node. – Martin Honnen Nov 15 '18 at 21:18