I am trying to use nested for-each-group and for-each with current-group() to compress like data into one xml record based on two keys. The first key being ID and second being Inv_Link
I am getting the expected results for the outer loop but the inner loop when I use //Record i get all keys in each result, with . i only get the first data element. Whats the proper selector to get all nested keys with in the parent key?
Thanks for any help!
XML Data Set
<Data>
<Record>
<ID>01_2019</ID>
<Link>ICE2</Link>
<Component_ID>DEBT</Component_ID>
<Amt>1500</Amt>
</Record>
<Record>
<ID>01_2019</ID>
<Link>ICE1</Link>
<Component_ID>EQT</Component_ID>
<Amt>200</Amt>
</Record>
<Record>
<ID>01_2019</ID>
<Link>ICE1</Link>
<Component_ID>CASH</Component_ID>
<Amt>100</Amt>
</Record>
<Record>
<ID>01_2020</ID>
<Link>ICE3</Link>
<Component_ID>CASH</Component_ID>
<Amt>100</Amt>
</Record>
</Data>
XSLT I'm using now:
<xsl:template match="Data">
<xsl:for-each-group select="Record" group-by="ID">
<xsl:for-each select="current-group()">
<Record>
<groupkey><xsl:value-of select="current-grouping-key()"/></groupkey>
<AssetEvent>
<ID> <xsl:copy> <xsl:value-of select="ID/text()" /> </xsl:copy> </ID>
<DecompositionSequence>
<xsl:for-each-group select="Record" group-by="Link">
<groupkey><xsl:value-of select="current-grouping-key()"/></groupkey>
<xsl:for-each select="current-group()">
<Decompositions>
<Link>
<ID><xsl:copy><xsl:value-of select="Link/text()" /> </xsl:copy> <ID>
</Link>
<DecompositionDataSequence>
<DecompositionData>
<Component>
<ID> <xsl:copy> <xsl:value-of select="Component_ID/text()" /> </xsl:copy> </ID>
</Component>
<Amt> <xsl:copy> <xsl:value-of select="Amt/text()" /> </xsl:copy> </Amt>
</DecompositionData>
</DecompositionDataSequence>
</Decompositions>
</xsl:for-each>
</xsl:for-each-group>
</DecompositionSequence>
</AssetEvent>
</Record>
</xsl:for-each>
</xsl:for-each-group>
</xsl:template>
Current Results, I get a total of 2 records but with none of the inner groupings (if i use //Record then i get all for both result records):
<Record>
<groupkey>ICE 01_2019</groupkey>
<AssetEvent>
<ID>ICE 01_2019</ID>
<DecompositionSequence />
</AssetEvent>
</Record>
<Record>
<groupkey>01_2020</groupkey>
<AssetEvent>
<ID>01_2020</ID>
<DecompositionSequence />
</AssetEvent>
</Record>
What I'm expecting:
<Record>
<groupkey>01_2019</groupkey>
<AssetEvent>
<ID>01_2019</ID>
<DecompositionSequence>
<groupkey>ICE2</groupkey>
<Decompositions>
<InvestmentLink>ICE2</InvestmentLink>
<DecompositionDataSequence>
<DecompositionData>
<Component>
<ID>DEBT</ID>
</Component>
<Amt>150</Amt>
</DecompositionData>
</DecompositionDataSequence>
</Decompositions>
<groupkey>ICE1</groupkey>
<Decompositions>
<InvestmentLink>ICE1</InvestmentLink>
<DecompositionDataSequence>
<DecompositionData>
<Component>
<ID>EQT</ID>
</Component>
<Amt>150</Amt>
</DecompositionData>
<DecompositionData>
<Component>
<ID>CASH</ID>
</Component>
<Amt>150</Amt>
</DecompositionData>
</DecompositionDataSequence>
</Decompositions>
</DecompositionSequence>
</AssetEvent>
</Record>
<Record>
<groupkey>01_2020</groupkey>
<AssetEvent>
<ID>01_2020</ID>
<DecompositionSequence>
<groupkey>ICE3</groupkey>
<Decompositions>
<InvestmentLink>ICE3</InvestmentLink>
<DecompositionDataSequence>
<DecompositionData>
<Component>
<ID>CASH</ID>
</Component>
<Amt>100</Amt>
</DecompositionData>
</DecompositionDataSequence>
</Decompositions>
</DecompositionSequence>
</AssetEvent>
</Record>
Assuming your input sample is
<Data>
<Record>
<ID>01_2019</ID>
<Link>ICE2</Link>
<Component_ID>DEBT</Component_ID>
<Amt>1500</Amt>
</Record>
<Record>
<ID>01_2019</ID>
<Link>ICE1</Link>
<Component_ID>EQT</Component_ID>
<Amt>200</Amt>
</Record>
<Record>
<ID>01_2019</ID>
<Link>ICE1</Link>
<Component_ID>CASH</Component_ID>
<Amt>100</Amt>
</Record>
<Record>
<ID>01_2020</ID>
<Link>ICE3</Link>
<Component_ID>CASH</Component_ID>
<Amt>100</Amt>
</Record>
</Data>
then the code
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="Data">
<xsl:for-each-group select="Record" group-by="ID">
<xsl:copy>
<groupkey>
<xsl:value-of select="current-grouping-key()"/>
</groupkey>
<AssetEvent>
<xsl:copy-of select="ID"/>
<DecompositionSequence>
<xsl:for-each-group select="current-group()" group-by="Link">
<groupkey>
<xsl:value-of select="current-grouping-key()"/>
</groupkey>
<Decompositions>
<InvestmentLink>
<xsl:value-of select="current-grouping-key()"/>
</InvestmentLink>
<DecompositionDataSequence>
<xsl:apply-templates select="current-group()"/>
</DecompositionDataSequence>
</Decompositions>
</xsl:for-each-group>
</DecompositionSequence>
</AssetEvent>
</xsl:copy>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="Record">
<DecompositionData>
<xsl:apply-templates select="* except (ID, Link)"/>
</DecompositionData>
</xsl:template>
<xsl:template match="Component_ID">
<Component>
<ID>
<xsl:value-of select="."/>
</ID>
</Component>
</xsl:template>
</xsl:stylesheet>
gives the output
<?xml version="1.0" encoding="UTF-8"?>
<Record>
<groupkey>01_2019</groupkey>
<AssetEvent>
<ID>01_2019</ID>
<DecompositionSequence>
<groupkey>ICE2</groupkey>
<Decompositions>
<InvestmentLink>ICE2</InvestmentLink>
<DecompositionDataSequence>
<DecompositionData>
<Component>
<ID>DEBT</ID>
</Component>
<Amt>1500</Amt>
</DecompositionData>
</DecompositionDataSequence>
</Decompositions>
<groupkey>ICE1</groupkey>
<Decompositions>
<InvestmentLink>ICE1</InvestmentLink>
<DecompositionDataSequence>
<DecompositionData>
<Component>
<ID>EQT</ID>
</Component>
<Amt>200</Amt>
</DecompositionData>
<DecompositionData>
<Component>
<ID>CASH</ID>
</Component>
<Amt>100</Amt>
</DecompositionData>
</DecompositionDataSequence>
</Decompositions>
</DecompositionSequence>
</AssetEvent>
</Record>
<Record>
<groupkey>01_2020</groupkey>
<AssetEvent>
<ID>01_2020</ID>
<DecompositionSequence>
<groupkey>ICE3</groupkey>
<Decompositions>
<InvestmentLink>ICE3</InvestmentLink>
<DecompositionDataSequence>
<DecompositionData>
<Component>
<ID>CASH</ID>
</Component>
<Amt>100</Amt>
</DecompositionData>
</DecompositionDataSequence>
</Decompositions>
</DecompositionSequence>
</AssetEvent>
</Record>
That uses the XSLT 3 declaration <xsl:mode on-no-match="shallow-copy"/>
but if you use an XSLT 2 processor you can replace it with the identity transformation template.