I am using XSLT for converting a XML derived from web and convert the same on the fly into the target xml file denoted as output . I am still unable to do so even after trying a lot , Can anyone please help me out with this conversion .
Source XML
<allocelement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<code>1111</code>
</allocelement>
<alloclement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1111</code>
</alloclement>
<alloclement>
<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1112</code>
</alloclement>
Output Desired
<allocelement>
<Codeheader>
<code>1111</code>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<alc>2</alc>
<amount>80000</amount>
</codeHeader>
<CodeHeader>
<code>1112</code>
<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
</CodeHeader>
</allocelement>
The Grouping is on the basis of Code,[hd1,hd2,hd3] such that the different elements within which have the same Code and [hd1,hd2,hd3] will be merged and only show fields which are different viz. the and . Also I am using xslt 1.0 .
A significantly shorter and simpler XSLT 1.0 solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kCodeByVal" match="code" use="."/>
<xsl:template match="/*">
<allocelement>
<xsl:apply-templates/>
</allocelement>
</xsl:template>
<xsl:template match="allocelement"/>
<xsl:template match=
"allocelement
[generate-id(code) = generate-id(key('kCodeByVal', code)[1])]">
<code><xsl:value-of select="code"/>
<xsl:copy-of select=
"node()[not(self::code)]
| key('kCodeByVal', code)/../*[self::alc or self::amount]"/>
</code>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document (a single top element wrapping the provided XML fragment):
<t>
<allocelement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<code>1111</code>
</allocelement>
<allocelement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1111</code>
</allocelement>
<allocelement>
<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1112</code>
</allocelement>
</t>
the wanted, correct result is produced:
<allocelement>
<code>1111<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<alc>2</alc>
<amount>80000</amount>
</code>
<code>1112<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
</code>
</allocelement>
Explanation: Proper use of the Muenchian grouping method.
II. XSLT 2.0 solution -- again shorter, and much more importantly -- syntactically and semantically correct:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<allocelement>
<xsl:for-each-group select="*" group-by="code">
<code><xsl:value-of select="code"/>
<xsl:sequence select=
"node()[not(self::code)]
| current-group()/*[self::alc or self::amount]"/>
</code>
</xsl:for-each-group>
</allocelement>
</xsl:template>
</xsl:stylesheet>
UPDATE: The OP has changed the requirements for the outpu.
Here is the corresponding modified XSLT 1.0 solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kCodeByVal" match="code" use="."/>
<xsl:template match="/*">
<allocelement>
<xsl:apply-templates/>
</allocelement>
</xsl:template>
<xsl:template match="allocelement"/>
<xsl:template match=
"allocelement
[generate-id(code) = generate-id(key('kCodeByVal', code)[1])]">
<codeHeader>
<code><xsl:value-of select="code"/></code>
<xsl:copy-of select=
"node()[not(self::code)]
| key('kCodeByVal', code)/../*[self::alc or self::amount]"/>
</codeHeader>
</xsl:template>
</xsl:stylesheet>