Reputation: 2452
I want to do a XSL transformation wherein I want group similar things.
But with the method like "key" "generate-id" I am not able to achieve this.
I am putting the source and expected format below.
I did have a look at this. So thought of relating the same example for simplification
Source:
<Root><!-- yes, I know I don't need a 'Root' element! Legacy code... -->
<Plans>
<Planner id="1">
<Plan AreaID="1"></Plan>
<Part ID="9122" Name="foo" />
<Part ID="9126" Name="bar" />
<Plan AreaID="1"></Plan>
<Part ID="8650" Name="baz" />
<Plan AreaID="2"></Plan>
<Part ID="215" Name="quux" />
<Plan AreaID="1" ></Plan>
<Part ID="7350" Name="meh" />
</Planner>
<Planner id="2">
<Plan AreaID="1"></Plan>
<Part ID="9122" Name="foo" />
<Part ID="9126" Name="bar" />
<Plan AreaID="1"></Plan>
<Part ID="8650" Name="baz" />
<Plan AreaID="2"></Plan>
<Part ID="215" Name="quux" />
<Plan AreaID="1" ></Plan>
<Part ID="7350" Name="meh" />
</Planner>
</Plans>
</Root>
Expected:
<Root><!-- yes, I know I don't need a 'Root' element! Legacy code... -->
<Plans>
<Planner id="1">
<Plan AreaID="1"></Plan>
<Part ID="9122" Name="foo" />
<Part ID="9126" Name="bar" />
<Part ID="8650" Name="baz" />
<Part ID="7350" Name="meh" />
<Plan AreaID="2"></Plan>
<Part ID="215" Name="quux" />
</Planner>
<Planner id="2">
<Plan AreaID="1"></Plan>
<Part ID="9122" Name="foo" />
<Part ID="9126" Name="bar" />
<Part ID="8650" Name="baz" />
<Part ID="7350" Name="meh" />
<Plan AreaID="2"></Plan>
<Part ID="215" Name="quux" />
</Planner>
</Plans>
</Root>
In my case since the Plan and Part are at the same level I am not able to group according to Plan which I want to do ideally.
Upvotes: 0
Views: 94
Reputation: 122374
The trick to getting Muenchian grouping to work in this situation where you want to group within a particular parent rather than globally, is to include something unique to the parent as part of the grouping key. Typically you would use generate-id(..)
but in this case you could simply use the id
attribute off the Planner
. For example
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*" />
<xsl:output indent="yes" />
<xsl:key name="partByArea" match="Part"
use="concat(../@id, '|', preceding-sibling::Plan[1]/@AreaID)" />
<!-- identity template - copy everything as-is except when overridden -->
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="Planner">
<xsl:copy>
<xsl:apply-templates select="@*" />
<!-- select the first Part in each group -->
<xsl:apply-templates mode="group" select="Part[generate-id() =
generate-id(key('partByArea',
concat(current()/@id, '|', preceding-sibling::Plan[1]/@AreaID))[1])]" />
</xsl:copy>
</xsl:template>
<!-- template applied to the first Part in each group -->
<xsl:template match="Part" mode="group">
<!-- the Plan that heads this group -->
<xsl:apply-templates select="preceding-sibling::Plan[1]" />
<!-- all the matching Part elements -->
<xsl:apply-templates select="key('partByArea',
concat(../@id, '|', preceding-sibling::Plan[1]/@AreaID))" />
</xsl:template>
</xsl:stylesheet>
Here we're grouping the Part
elements by a combination of the id
of their parent Planner
and the AreaID
of their nearest preceding Plan
.
Upvotes: 4