0

Im now to XSLT and I need to do some grouping with the value of a child. I have objects, that can have multiple properties and one of them (with id=11) is on I need to use as a grouping element. The amount of properties each object can have varies, but they all have the common prop.

Input:

<object id=1>
 <properties>
    <prop id=10>Name of object 1</prop>
    <prop id=11>Group 1</prop>
    <prop id=xy>Whatever properties this object has</prop>
 </properties>
</object>
<object id=2>
 <properties>
    <prop id=10>Name of object 2</prop>
    <prop id=11>Group 2</prop>
 </properties>
</object>
<object id=3>
 <properties>
    <prop id=10>Name of object 3</prop>
    <prop id=11>Group 1</prop>
 </properties>
</object>
<object id=4>
 <properties>
    <prop id=10>Name of object 4</prop>
    <prop id=11>Group 3</prop>
 </properties>
</object>

Desired output:

<group name='Group 1'>
  <object id=1>
    <prop id=10>Name of object 1</prop>
    <prop id=11>Group 1</prop>
    <prop id=xy>Whatever properties this object has</prop>
  </object>
<object id=3>
 <properties>
    <prop id=10>Name of object 3</prop>
    <prop id=11>Group 1</prop>
 </properties>
</object>
</group>
<group name='Group 2'>
  <object id=2>
   <properties>
    <prop id=10>Name of object 2</prop>
    <prop id=11>Group 2</prop>
   </properties>
  </object>
</group>
<group name='Group 3'>
  <object id=4>
   <properties>
    <prop id=10>Name of object 4</prop>
    <prop id=11>Group 3</prop>
   </properties>
  </object>
</group>

The idea is to have the items grouped by the value of the prop with id 11.

Ive found multiple different code samples, but none of them have had this specific case, and I havent been able to modify them to suit my need.

Kemu79
  • 187
  • 1
  • 9

2 Answers2

2

My version of the xsl that is essentially that same as Michael Vehrs in that it is also using the Muenchian Method but thought I may as well post it to show a subtle alternative. Here I'm using an apply-templates instead of the for-each/call-template. In terms of performance there is probably nothing between them but personally, I prefer to use apply-templates wherever possible as it typically allows for more flexibility.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no" encoding="utf-8"/>
<xsl:key name="groups" match="prop[@id='11']" use="text()"/>

<xsl:template match="/">
    <xsl:apply-templates select="//prop[generate-id()=generate-id(key('groups', text())[1])]"/>
</xsl:template>

<xsl:template match="prop">
    <group name="{text()}">
        <xsl:copy-of select="//object[properties/prop[@id='11']=current()/text()]"/>
    </group>
</xsl:template>

</xsl:stylesheet>
Phil Blackburn
  • 1,047
  • 1
  • 8
  • 13
1

This is a basic application of the Muenchian Method (which is explained here, for example):

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="prop" match="//prop[@id='11']/text()" use="." />

<xsl:template match="/">
  <xsl:for-each select="//prop[@id='11']/text()[generate-id()
                        = generate-id(key('prop',.)[1])]">
    <xsl:call-template name="group">
      <xsl:with-param name="groupname" select="." />
    </xsl:call-template>
  </xsl:for-each>
</xsl:template>

<xsl:template name="group">
  <xsl:param name="groupname" />
  <group><xsl:attribute name="name"><xsl:value-of select='$groupname'/></xsl:attribute>
  <xsl:for-each select="//object[.//prop[@id='11'][text()=$groupname]]" >
    <xsl:copy-of select="." />
  </xsl:for-each>
  </group>
</xsl:template>

</xsl:stylesheet>
Michael Vehrs
  • 3,293
  • 11
  • 10