Reputation: 17
I have a sample XML to which I need to transform to combine nodes with the same Archived_Employee_ID. The XSLT which I created already works but I'm looking for a more clean solution which is high performing using XSLT3.0 since I'm expecting huge data load.
XSLT I'm using:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wd="ur">
<xsl:output omit-xml-declaration="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="wd:Report_Data">
<wd:Report_Data>
<xsl:for-each-group select="wd:Report_Entry" group-by="wd:Archived_Employee_ID">
<wd:Report_entry>
<wd:Archived_Employee_ID>
<xsl:value-of select="wd:Archived_Employee_ID"/>
</wd:Archived_Employee_ID>
<xsl:call-template name="Fix"/>
</wd:Report_entry>
</xsl:for-each-group>
</wd:Report_Data>
</xsl:template>
<xsl:template name="Fix">
<wd:AE_group>
<xsl:variable name="AE">
<xsl:value-of select="distinct-values(current-group()/wd:Archived_Expectation)"
separator="§"/>
</xsl:variable>
<xsl:for-each select="tokenize($AE, '§')">
<wd:Archived_Expectation>
<xsl:value-of select="."/>
</wd:Archived_Expectation>
</xsl:for-each>
</wd:AE_group>
<wd:AE_Category_Group>
<xsl:variable name="Category">
<xsl:value-of select="(current-group()/wd:Archived_Expectation_Category)"
separator="§"/>
</xsl:variable>
<xsl:for-each select="tokenize($Category, '§')">
<wd:Archived_Expectation_Category>>
<xsl:value-of select="."/>
</wd:Archived_Expectation_Category>>
</xsl:for-each>
</wd:AE_Category_Group>
</xsl:template>
</xsl:stylesheet>
Here is sample XML:
<?xml version='1.0' encoding='UTF-8'?>
<wd:Report_Data xmlns:wd="ur">
<wd:Report_Entry>
<wd:Archived_Employee_ID>XYZ</wd:Archived_Employee_ID>
<wd:Archived_Expectation>Increase complaint statistics.</wd:Archived_Expectation>
<wd:Archived_Expectation_Category>Roles, Responsibilities &
Competencies</wd:Archived_Expectation_Category>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Archived_Employee_ID>XYZ</wd:Archived_Employee_ID>
<wd:Archived_Expectation>Verantwortungsbereich</wd:Archived_Expectation>
<wd:Archived_Expectation_Category> Competencies</wd:Archived_Expectation_Category>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Archived_Employee_ID>123</wd:Archived_Employee_ID>
<wd:Archived_Expectation>Verantwortungsbereich: 5%</wd:Archived_Expectation>
<wd:Archived_Expectation_Category> Role</wd:Archived_Expectation_Category>
</wd:Report_Entry>
</wd:Report_Data>
Expected Output:
<wd:Report_Data xmlns:wd="ur">
<wd:Report_entry>
<wd:Archived_Employee_ID>XYZ</wd:Archived_Employee_ID>
<wd:AE_group>
<wd:Archived_Expectation>Increase complaint statistics.</wd:Archived_Expectation>
<wd:Archived_Expectation>Verantwortungsbereich</wd:Archived_Expectation>
</wd:AE_group>
<wd:AE_Category_Group><wd:Archived_Expectation_Category>Roles, Responsibilities &
Competencies</wd:Archived_Expectation_Category>
<wd:Archived_Expectation_Category>
Competencies</wd:Archived_Expectation_Category></wd:AE_Category_Group>
</wd:Report_entry>
<wd:Report_entry>
<wd:Archived_Employee_ID>123</wd:Archived_Employee_ID>
<wd:AE_group>
<wd:Archived_Expectation>Verantwortungsbereich: 5%</wd:Archived_Expectation>
</wd:AE_group>
<wd:AE_Category_Group><wd:Archived_Expectation_Category>
Role</wd:Archived_Expectation_Category> </wd:AE_Category_Group>
</wd:Report_entry>
</wd:Report_Data>
Upvotes: 0
Views: 310
Reputation: 167471
There is not much you can cleanly and purely stream here as you want to use for-each-group group-by
with a group-by
expression selecting a child element (which is not "motionless") so the only way is to use copy-of()
in the grouping population
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="ur" xmlns:wd="ur">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes"/>
<xsl:template match="Report_Data">
<xsl:copy>
<xsl:for-each-group select="Report_Entry!copy-of()" group-by="Archived_Employee_ID">
<xsl:copy>
<xsl:copy-of select="Archived_Employee_ID"/>
<wd:AE_group>
<xsl:for-each-group select="current-group()/Archived_Expectation" group-by=".">
<xsl:copy-of select="." />
</xsl:for-each-group>
</wd:AE_group>
<wd:AE_Category_Group>
<xsl:for-each-group select="current-group()/Archived_Expectation_Category" group-by=".">
<xsl:copy-of select="." />
</xsl:for-each-group>
</wd:AE_Category_Group>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 338148
Since you're effectively grouping in your <xsl:template name="Fix">
, I don't understand why you're not using for-each-group
<xsl:template name="Fix">
<wd:AE_group>
<xsl:for-each-group select="current-group()/wd:Archived_Expectation" group-by=".">
<xsl:copy-of select="." />
</xsl:for-each-group>
</wd:AE_group>
<wd:AE_Category_Group>
<xsl:for-each-group select="current-group()/wd:Archived_Expectation_Category" group-by=".">
<xsl:copy-of select="." />
</xsl:for-each-group>
</wd:AE_Category_Group>
</xsl:template>
You could also loop over distinct-values()
if you prefer (I wouldn't):
<xsl:for-each select="distinct-values(current-group()/wd:Archived_Expectation)">
<wd:Archived_Expectation>
<xsl:copy-of select="." />
</wd:Archived_Expectation>
</xsl:for-each>
Upvotes: 2