0

I got task to modify tool made by some other guy who left the company some time ago. Last thing left to do is the grouping part of XML by date. Every example I found works with XML with attributes so it's not really that helpful.

My XML does not have single attribute and its structure is something like this:

<report>
<clientInfo>
...
</clientInfo>
<bills>
    <bill>
        <section>
            <dateSegment>20-07-1990</dateSegment>
            <money>100</money>
            <days>9</days>
        </section>
        <section>
            <dateSegment>20-08-1990</dateSegment>
            <money>130</money>
            <days>4</days>
        </section>
        <section>
            <dateSegment>20-09-1990</dateSegment>
            <money>110</money>
            <days>5</days>
        </section>
    </bill>
    <bill>
        <section>
            <dateSegment>20-07-1990</dateSegment>
            <money>230</money>
            <days>11</days>
        </section>
        <section>
            <dateSegment>20-10-1990</dateSegment>
            <money>210</money>
            <days>3</days>
        </section>
    </bill>
    ...
</bills>
...
</report>

I have to group by same date and sum up per each group. I tried writing template according to how to apply group by on xslt elements post but it's far from working as intended.

<xsl:key name="by_date" match="section" use="@dateSegment" />

<xsl:template name="test">
    <xsl:element name="AllSections">
        <xsl:for-each-group select="*" group-by="@dateSegment">
            <xsl:element name="dateSegment">
                <xsl:attribute name="value">
                    <xsl:value-of select="@dateSegment" />
                </xsl:attribute>
                <xsl:for-each select="current-group()">
                    <xsl:element name="section">
                        <xsl:element name="money"><xsl:value-of select="@money" /></xsl:element>
                        <xsl:element name="days"><xsl:value-of select="@days" /></xsl:element>
                    </xsl:element>
                </xsl:for-each>
              </xsl:element>
       </xsl:for-each-group>
    </xsl:element>
</xsl:template>

Tried calling it with <xsl:call-template name="test"/> but nothing happens, result is null.

Expected output:

Either

<dateSegment value="20-07-1990">
    <section>
        <money>100</money>
        <days>9</days>
    </section>
    <section>
        <money>230</money>
        <days>11</days>
    </section>
</dateSegment>
<dateSegment value="20-08-1990">
    <section>
        <money>130</money>
        <days>4</days>
    </section>
</dateSegment>
...

or

<dateSegment>
    <money>340</money>
    <days>11</days> (max value from <days> in same section)
</dateSegment>
<dateSegment>   
    <money>130</money>
    <days>4</days>
    </section>
</dateSegment>

Would be helpful to assign that XML to variable so I could do stuff with it.

Alrdy asked everyone I could but none of us works with such things and no one was able to help me out.

Any idea how to do it?

Dashovsky
  • 137
  • 9

1 Answers1

1

Firstly, you mention about not having attributes, yet the XSLT is still using the attribute syntax; i.e. @dateSegment. It should be dateSegment to refer to the element.

It also looks like you want to group section elements, regardless of what bill element they are in (as opposed to doing separate grouping within each bill element). But your current XSLT is doing <xsl:for-each-group select="*" which will really only give you results if you are on a bill element. Really, you want to be positioned on the bills element, and do this:

<xsl:for-each-group select="bill/section" group-by="dateSegment">

Try this XSLT (which I have simplified to remove the use of xsl:element and xsl:attribute)

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

<xsl:output method="xml" indent="yes" />

<xsl:template match="bills">
    <AllSections>
        <xsl:for-each-group select="bill/section" group-by="dateSegment">
            <dateSegment value="{dateSegment}">
                <xsl:for-each select="current-group()">
                    <section>
                        <money><xsl:value-of select="money" /></money>
                        <days><xsl:value-of select="days" /></days>
                    </section>
                </xsl:for-each>
            </dateSegment>
        </xsl:for-each-group>
    </AllSections>
</xsl:template>

</xsl:stylesheet>

And if you want to aggregate your results, do this

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

<xsl:output method="xml" indent="yes" />

<xsl:template match="bills">
    <AllSections>
        <xsl:for-each-group select="bill/section" group-by="dateSegment">
            <dateSegment value="{dateSegment}">
                <money><xsl:value-of select="sum(current-group()/money)" /></money>
                <days><xsl:value-of select="max(current-group()/days)" /></days>
            </dateSegment>
        </xsl:for-each-group>
    </AllSections>
</xsl:template>

</xsl:stylesheet>
Tim C
  • 70,053
  • 14
  • 74
  • 93
  • thanks a lot Tim, trying to apply this to my code. Do you know if its possible to assign that aggregated XML to a variable? – Dashovsky Aug 02 '18 at 11:57
  • Well I used the template (with only sum part) with and it returned the sum of money but I wasn't able to see transformed XML – Dashovsky Aug 02 '18 at 13:00
  • Do ``. Doing `xsl:value-of` only returns the string value of what you select. – Tim C Aug 02 '18 at 13:03
  • Well it didnt change, im still getting sum returned – Dashovsky Aug 02 '18 at 13:11
  • See http://xsltfiddle.liberty-development.net/nc4NzQy , although I am not entirely clear what you are trying to achieve here. – Tim C Aug 02 '18 at 13:15
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/177285/discussion-between-dashovsky-and-tim-c). – Dashovsky Aug 02 '18 at 13:40