Subject: Re: Create xml file with recursive childnodes
From: "Mukul Gandhi" <gandhi.mukul@xxxxxxxxx>
Date: Thu, 14 Aug 2008 09:27:56 +0530
|
Hi Chun,
Thanks for pointing the error. Below is the stylesheet, which has this fix ...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="Objs">
<xsl:variable name="start" select="obj[not(@name = ../obj/@child)]" />
<xsl:variable name="startName" select="distinct-values($start/@name)" />
<Obj name="{$startName}">
<xsl:for-each select="obj[(@name = $startName) and not(../obj/@name
= @child)]">
<Obj name="{@child}" />
</xsl:for-each>
<xsl:call-template name="makeTree">
<xsl:with-param name="list" select="obj[@name = $start/@child]" />
</xsl:call-template>
</Obj>
</xsl:template>
<xsl:template name="makeTree">
<xsl:param name="list" />
<Obj name="{$list[1]/@name}">
<xsl:for-each select="$list">
<xsl:variable name="child" select="@child" />
<xsl:choose>
<xsl:when test="not(../obj[@name = $child])">
<Obj name="{$child}" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="makeTree">
<xsl:with-param name="list" select="../obj[@name = $child]" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Obj>
</xsl:template>
</xsl:stylesheet>
I think, we don't really need for-each-group. I have modified the
stylesheet accordingly, using a normal for-each loop.
Kindly do report any bugs in this version, and I'll attempt to solve it.
On 8/14/08, chun ji <cji_work@xxxxxxxxx> wrote:
> Hi Mukul,
> thank you for 2 solutions. But I see an issue for the
> second one if the root obj has more that 1 child.
>
> For example, if the input xml is :
> "
> <Objs>
> <obj name="a" child="b"/>
> <obj name="b" child="c"/>
> <obj name="b" child="d"/>
> <obj name="c" child="e"/>
> <obj name="b" child="f"/>
> <obj name="a" child="u"/>
> </Objs>
> "
> , I get such results
>
> "
> <?xml version="1.0" encoding="UTF-8"?>
> <Obj name="a a">
> <Obj name="b">
> <Obj name="c">
> <Obj name="e"/>
> </Obj>
> <Obj name="d"/>
> <Obj name="f"/>
> </Obj>
> </Obj>
> ".
>
>
> Regards,
>
>
>
> Chun
>
>
>
>
>
>
> --- Mukul Gandhi <gandhi.mukul@xxxxxxxxx> wrote:
>
> > Here is a slightly better solution.
> >
> > <xsl:stylesheet
> > xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> > version="2.0">
> >
> > <xsl:output method="xml" indent="yes" />
> >
> > <xsl:template match="Objs">
> > <xsl:variable name="start" select="obj[not(@name =
> > ../obj/@child)]" />
> > <Obj name="{$start/@name}">
> > <xsl:choose>
> > <xsl:when test="not(obj[@name =
> > $start/@child])">
> > <Obj name="{$start/@child}" />
> > </xsl:when>
> > <xsl:otherwise>
> > <xsl:call-template name="performGrouping">
> > <xsl:with-param name="list"
> > select="obj[@name = $start/@child]" />
> > </xsl:call-template>
> > </xsl:otherwise>
> > </xsl:choose>
> > </Obj>
> > </xsl:template>
> >
> > <xsl:template name="performGrouping">
> > <xsl:param name="list" />
> >
> > <xsl:for-each-group select="$list"
> > group-by="@name">
> > <Obj name="{current-grouping-key()}">
> > <xsl:for-each select="current-group()">
> > <xsl:variable name="child" select="@child"
> > />
> > <xsl:choose>
> > <xsl:when test="not(../obj[@name =
> > $child])">
> > <Obj name="{$child}" />
> > </xsl:when>
> > <xsl:otherwise>
> > <xsl:call-template
> > name="performGrouping">
> > <xsl:with-param name="list" select="../obj[@name =
> > $child]" />
> > </xsl:call-template>
> > </xsl:otherwise>
> > </xsl:choose>
> > </xsl:for-each>
> > </Obj>
> > </xsl:for-each-group>
> > </xsl:template>
> >
> > </xsl:stylesheet>
> >
> > The stylesheet I earlier posted did execution in two
> > pass. This one
> > does the whole processing in a single pass.
> >
> > On Sat, Aug 9, 2008 at 10:44 AM, Mukul Gandhi
> > <gandhi.mukul@xxxxxxxxx> wrote:
> > > The following stylesheet works ...
> >
> > --
> > Regards,
> > Mukul Gandhi
--
Regards,
Mukul Gandhi
|