XSLT 3.0 Streaming with Grouping and Sum/Accumulator

Viewed 2968

I'm trying to figure out how to use XSLT Streaming (to reduce memory usage) in a scenario that requires grouping (with an arbitrary number of groups) and summing the group. So far I haven't been able to find any examples. Here's an example XML

<?xml version='1.0' encoding='UTF-8'?>
  <Data>
    <Entry>
      <Genre>Fantasy</Genre>
      <Condition>New</Condition>
      <Format>Hardback</Format>
      <Title>Birds</Title>
      <Count>3</Count>
    </Entry>
    <Entry>
      <Genre>Fantasy</Genre>
      <Condition>New</Condition>
      <Format>Hardback</Format>
      <Title>Cats</Title>
      <Count>2</Count>
    </Entry>
    <Entry>
      <Genre>Non-Fiction</Genre>
      <Condition>New</Condition>
      <Format>Paperback</Format>
      <Title>Dogs</Title>
      <Count>4</Count>
    </Entry>
 </Data>

In XSLT 2.0 I would use this to group by Genre, Condition and Format and Sum the counts.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="yes" />
  <xsl:template match="/">
     <xsl:call-template name="body"/>
  </xsl:template>
  <xsl:template name="body">
    <xsl:for-each-group select="Data/Entry" group-by="concat(Genre,Condition,Format)">
      <xsl:value-of select="Genre"/>
      <xsl:value-of select="Condition"/>
      <xsl:value-of select="Format"/>
      <xsl:value-of select="sum(current-group()/Count)"/>
    </xsl:for-each-group>
  </xsl:template>
</xsl:stylesheet>

For output I would get two lines, a sum of 5 for Fantasy, New, Hardback and a sum of 4 for Non-Fiction, New, Paperback.

Obviously this won't work with Streaming because the sum accesses the whole group. I think I need to iterate through the document twice. The first time I could build a map of the groups (creating a new group if one doesn't exist yet). The second time The problem is I also need an accumulator for each group with a rule that matches the group, and it doesn't seem you can create dynamic accumulators.

Is there a way to create accumulators on the fly? Is there another/easier way to do this with Streaming?

1 Answers
Related