I am trying to group the input XML as per country code. The grouping function is working but I'm not able get all the nodes. Issue: I'm missing other two nodes of a specific country. Please review my code. Using current-group() only shows child nodes and misses wd:ID node.
Thanks! HB
Input XML
<wd:Report_Data xmlns:wd="urn:com.xyz">
<wd:Report_Entry>
<wd:Worker>
<wd:Worker wd:Descriptor="Mark">
</wd:Worker>
<wd:CF_Country_code_2>DE</wd:CF_Country_code_2>
</wd:Worker>
<wd:ID wd:type="Employee_ID">12</wd:ID>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Worker>
<wd:Worker wd:Descriptor="Jack">
</wd:Worker>
<wd:CF_Country_code_2>DE</wd:CF_Country_code_2>
</wd:Worker>
<wd:ID wd:type="Employee_ID">34</wd:ID>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Worker>
<wd:Worker wd:Descriptor="Miguel">
</wd:Worker>
<wd:CF_Country_code_2>ES</wd:CF_Country_code_2>
</wd:Worker>
<wd:ID wd:type="Employee_ID">67</wd:ID>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Worker>
<wd:Worker wd:Descriptor="Chris">
</wd:Worker>
<wd:CF_Country_code_2>ES</wd:CF_Country_code_2>
</wd:Worker>
<wd:ID wd:type="Employee_ID">89</wd:ID>
</wd:Report_Entry>
My XSLT code
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:wd="urn:com.xyz">
<xsl:template match="wd:Report_Data">
<ROOT>
<xsl:for-each-group select="wd:Report_Entry/wd:Worker"
group-by="wd:CF_Country_code_2">
<wd:Report_Data>
<xsl:copy-of select=".." />
</wd:Report_Data>
</xsl:for-each-group>
</ROOT>
</xsl:template>
Expected output:
<ROOT>
<wd:Report_Data xmlns:wd="urn:com.xyz">
<wd:Report_Entry>
<wd:Worker>
<wd:Worker wd:Descriptor="Mark">
</wd:Worker>
<wd:CF_Country_code_2>DE</wd:CF_Country_code_2>
</wd:Worker>
<wd:ID wd:type="Employee_ID">12</wd:ID>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Worker>
<wd:Worker wd:Descriptor="Jack">
</wd:Worker>
<wd:CF_Country_code_2>DE</wd:CF_Country_code_2>
</wd:Worker>
<wd:ID wd:type="Employee_ID">34</wd:ID>
</wd:Report_Entry>
</wd:Report_Data>
<wd:Report_Data xmlns:wd="urn:com.xyz">
<wd:Report_Entry>
<wd:Worker>
<wd:Worker wd:Descriptor="Miguel">
</wd:Worker>
<wd:CF_Country_code_2>ES</wd:CF_Country_code_2>
</wd:Worker>
<wd:ID wd:type="Employee_ID">67</wd:ID>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Worker>
<wd:Worker wd:Descriptor="Chris">
</wd:Worker>
<wd:CF_Country_code_2>ES</wd:CF_Country_code_2>
</wd:Worker>
<wd:ID wd:type="Employee_ID">89</wd:ID>
</wd:Report_Entry>
</wd:Report_Data>
You could change the grouping to
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="urn:com.xyz"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:template match="/">
<Root>
<xsl:for-each-group select="Report_Data/Report_Entry" group-by="Worker/CF_Country_code_2">
<xsl:copy select="..">
<xsl:apply-templates select="current-group()"/>
</xsl:copy>
</xsl:for-each-group>
</Root>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/93dFeq1
That is XSLT 3 as supported since Saxon 9.8 all editions or Altova XML 2017 R3.
In XSLT 2 you can use <xsl:copy select="..">
but you can use <xsl:element name="{name(..)}" namespace="{namespace-uri(..)}">
instead.
And of course instead of declaring the identity transformation as the base processing with xsl:mode
you can spell it out as a template
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>