I am trying to transform one XML by creating a new tag by grouping the tags. like group the items which are having same parent value.
<root>
<item id="100">
<properties>
<property attribute-id="parent">10</property>
</properties>
<properties>
<property attribute-id="amount">1.1</property>
</properties>
</item>
<item id="101">
<properties>
<property attribute-id="parent">10</property>
</properties>
<properties>
<property attribute-id="amount">1.1</property>
</properties>
</item>
<item id="102">
<properties>
<property attribute-id="parent">11</property>
</properties>
<properties>
<property attribute-id="amount">1.1</property>
</properties>
</item>
<item id="103">
<properties>
<property attribute-id="parent">10</property>
</properties>
<properties>
<property attribute-id="amount">1.1</property>
</properties>
</item>
<item id="104">
<properties>
<property attribute-id="parent">11</property>
</properties>
<properties>
<property attribute-id="amount">1.1</property>
</properties>
</item>
</root>
New tag should be:
<item id = "10">
<childs>
<child id="100" />
<child id="101" />
<child id="102" />
</childs>
</item>
<item id = "11">
<childs>
<child id="104" />
<child id="105" />
</childs>
</item>
Is this possible with XSLT?
How can this be done in XSLT?
Editing the initial post i have faced some issues when the tag was in attribute format. Tried updating the first solution but the attribute form is causing many problems.
You can achieve with this the XSLT-1.0 method Muenchian Grouping. If you search on SO, you'll find a lot of examples. Applying this method, your stylesheet could look like this (I added a hypothetical <root>
element around your source XML to make it well-formed):
The xsl:key
and the select
expression of the outer xsl:for-each
do implement the Muenchian Grouping. The inside of the loop should be kind of self-explaining.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="id" match="item" use="properties/property[@attribute-id='parent']" />
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each select="item[generate-id() = generate-id(key('id',properties/property[@attribute-id='parent'])[1])]">
<item id="{parent}">
<childs>
<xsl:for-each select="key('id',properties/property[@attribute-id='parent'])">
<child id="{@id}" />
</xsl:for-each>
</childs>
</item>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If you can use XSLT-2.0 or above, you can make use of xsl:for-each-group
like this:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each-group select="item" group-by="properties/property[@attribute-id='parent']">
<item id="{parent}">
<childs>
<xsl:for-each select="current-group()">
<child id="{@id}" />
</xsl:for-each>
</childs>
</item>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
It is slightly more simple, but does the same.
Its output, in both cases, is:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item id="">
<childs>
<child id="100"/>
<child id="101"/>
<child id="103"/>
</childs>
</item>
<item id="">
<childs>
<child id="102"/>
<child id="104"/>
</childs>
</item>
</root>
It's not exactly what you want, but I guess that the last child
id's of your example are wrong.