I am trying to produce a nested XML document from a flat XML document as below. After searching here and other resources available on the net it seems that that the muenchain method could be the solution however I am struggling applying it to my situation.
The XML I need to translate is of form :
<i>
<item id="1" name="one" sub_id="10" sub_name="s1" detail_id="t1" detail_name="aaaa"/>
<item id="1" name="one" sub_id="10" sub_name="s1" detail_id="t2" detail_name="bbb"/>
<item id="1" name="one" sub_id="20" sub_name="s2" detail_id="t1" detail_name="ccc"/>
<item id="1" name="one" sub_id="20" sub_name="s2" detail_id="t2" detail_name="ddd"/>
<item id="2" name="two" sub_id="10" sub_name="s1" detail_id="t1" detail_name="eee"/>
<item id="2" name="two" sub_id="10" sub_name="s1" detail_id="t2" detail_name="fff"/>
<item id="2" name="two" sub_id="20" sub_name="s2" detail_id="t1" detail_name="ggg"/>
<item id="2" name="two" sub_id="20" sub_name="s2" detail_id="t2" detail_name="hhh"/>
<item id="3" name="three" />
<item id="4" name="four" sub_id="10" sub_name="s1" detail_id="t1" detail_name="mmm"/>
<item id="4" name="four" sub_id="10" sub_name="s1" detail_id="t2" detail_name="nnn"/>
<item id="4" name="four" sub_id="20" sub_name="s2" detail_id="t1" detail_name="ooo"/>
<item id="4" name="four" sub_id="20" sub_name="s2" detail_id="t2" detail_name="ppp"/>
</i>
I would like to tranform this to XML in the following form:
<i>
<item id="1" name="one" sub_items="true">
<sub_item sub_id="10" sub_name="s1">
<detail detail_id="t1" detail_name="aaaa"/>
<detail detail_id="t2" detail_name="bbb"/>
</sub_item>
<sub_item sub_id="20" sub_name="s2">
<detail detail_id="t1" detail_name="ccc"/>
<detail detail_id="t2" detail_name="ddd"/>
</sub_item>
</item>
<item id="2" name="two" sub_items="true">
<sub_item sub_id="10" sub_name="s1">
<detail detail_id="t1" detail_name="eee"/>
<detail detail_id="t2" detail_name="fff"/>
</sub_item>
<sub_item sub_id="20" sub_name="s2">
<detail detail_id="t1" detail_name="ggg"/>
<detail detail_id="t2" detail_name="hhh"/>
</sub_item>
</item>
<item id="3" name="three" sub_items="false"/>
<item id="4" name="four" sub_items="true">
<sub_item sub_id="10" sub_name="s1">
<detail detail_id="t1" detail_name="mmm"/>
<detail detail_id="t2" detail_name="nnn"/>
</sub_item>
<sub_item sub_id="20" sub_name="s2">
<detail detail_id="t1" detail_name="ooo"/>
<detail detail_id="t2" detail_name="ppp"/>
</sub_item>
</item>
</i>
From my research I have the following XLST to perform the transform. I use the key method on the item id attribute. This doesn't group the data correctly repeating everything for the given item id at each level - which makes sense given the key. So my problem is how do I go about selecting the nodes required to output each nest level do I need to use another key statement?
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="indexes" match="i/item" use="@id"/>
<xsl:template match="i">
<i>
<xsl:for-each select="item[count(. | key('indexes',@id)[1]) = 1]" >
<xsl:sort select="@id"/>
<item>
<xsl:attribute name="id">
<xsl:value-of select="@id"/>
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:attribute name="hasRows">
<xsl:value-of select="@id"/>
</xsl:attribute>
<xsl:for-each select="key('indexes',@id)">
<subitem>
<xsl:attribute name ="sub_id">
<xsl:value-of select="@sub_id"/>
</xsl:attribute>
<xsl:attribute name ="sub_name">
<xsl:value-of select="@sub_name"/>
</xsl:attribute>
<xsl:for-each select="key('indexes',@id)">
<segment>
<xsl:attribute name ="detail_id">
<xsl:value-of select="@detail_id"/>
</xsl:attribute>
<xsl:attribute name ="detail_name">
<xsl:value-of select="@detail_name"/>
</xsl:attribute>
</segment>
</xsl:for-each>
</subitem>
</xsl:for-each>
</item>
</xsl:for-each>
</i>
</xsl:template>
</xsl:stylesheet>
Also is it possible to populate the *sub_items* attribute with true when subitems/details for an item exist and false when they don't?
Lastly to improve XSLT understanding/skills can anyone recommend good learning resources?
The Muenchian method is tricky for nested grouping. The first level of grouping is easy to manage, but for the others you have to index elements with compound keys composed with previous ids.
Notice this XSLT 1.0 transform with use of:
extensive use of
xsl:apply-templates
with modes, versusxsl:for-each
Applied on the input shown in your question, produces: