Re: [xsl] XSLT recursion problem

Subject: Re: [xsl] XSLT recursion problem
From: "M. David Peterson" <m.david.x2x2x@xxxxxxxxx>
Date: Wed, 28 Sep 2005 04:11:57 -0600
> group together child cousins,

Uh, that would just be cousins...  I started to write child and change
my mind to cousin... helps if you delete the word you don't wan't,
doesnt it :D

On 9/28/05, M. David Peterson <m.david.x2x2x@xxxxxxxxx> wrote:
> Actually, I misread your desired output... this actually elimates two
> lines of code, but increases processing time because of crawling back
> up the tree to get the value of the parents @element.  But, its not a
> huge deal unless you are processing heavy amounts of input where
> performance is crucial...
>
> The updated code (still dependent on position... again, you need to
> have something that make coding fun... having ALL the answers spoon
> fed doesn't help you understand how it works, but having pieces of the
> puzzle definitely helps... as such heres piece two of three pieces to
> make this completely non dependent on the count of the parent elements
> as well as increase performance by a decent chunk...  keep in mind,
> you're attempting to group together child cousins, in birth order...
> grouping almost always points to a particular way of doing things...
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> xmlns:ax="uri:axnamespace"
>     version="1.0">
>     <xsl:template match="/">
>         <xsl:apply-templates select="ax:repeat/*" mode="initial"/>
>     </xsl:template>
>     <xsl:template match="*" mode="initial">
>         <xsl:apply-templates select="*" mode="universal">
>             <xsl:with-param name="name" select="name()"/>
>         </xsl:apply-templates>
>     </xsl:template>
>     <xsl:template match="*" mode="universal">
>         <xsl:param name="name"/>
>         <xsl:variable name="position" select="position()"/>
>         <xsl:element name="{$name}">
>             <xsl:apply-templates select="../*/*[position() =
> $position]" mode="parent"/>
>         </xsl:element>
>     </xsl:template>
>     <xsl:template match="*" mode="parent">
>         <xsl:param name="name"/>
>         <xsl:param name="parentName"/>
>         <xsl:element name="{$parentName}">
>             <xsl:apply-templates select="." mode="child">
>                 <xsl:with-param name="name" select="$name"/>
>             </xsl:apply-templates>
>         </xsl:element>
>     </xsl:template>
>     <xsl:template match="*" mode="child">
>         <xsl:element name="{parent::*/@element}">
>             <xsl:copy-of select="@*"/>
>         </xsl:element>
>     </xsl:template>
> </xsl:stylesheet>
>
> produces:
>
> <?xml version="1.0" encoding="utf-8"?>
> <sometag>
>    <txt src="txt1.txt"/>
>    <img src="img1.jpg"/>
> </sometag>
> <sometag>
>    <txt src="txt2.txt"/>
>    <img src="img2.jpg"/>
> </sometag>
>
> which is what you had in your sample...
>
> Enjoy!
>
> On 9/28/05, M. David Peterson <m.david.x2x2x@xxxxxxxxx> wrote:
> > You can:
> >
> > In XSLT 1.0 this:
> >
> > <?xml version="1.0" encoding="UTF-8"?>
> > <ax:repeat xmlns:ax="uri:axnamespace">
> >     <sometag>
> >         <ax:items element="txt">
> >             <ax:item src="txt1.txt"/>
> >             <ax:item src="txt2.txt"/>
> >         </ax:items>
> >         <ax:items element="img">
> >             <ax:item src="img1.jpg"/>
> >             <ax:item src="img2.jpg"/>
> >         </ax:items>
> >     </sometag>
> > </ax:repeat>
> >
> > Processed by this:
> >
> >
> > <?xml version="1.0" encoding="UTF-8"?>
> > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> > xmlns:ax="uri:axnamespace"
> >     version="1.0">
> >     <xsl:template match="/">
> >         <xsl:apply-templates select="ax:repeat/*" mode="initial"/>
> >     </xsl:template>
> >     <xsl:template match="*" mode="initial">
> >         <xsl:apply-templates select="*" mode="universal">
> >             <xsl:with-param name="name" select="name()"/>
> >         </xsl:apply-templates>
> >     </xsl:template>
> >     <xsl:template match="*" mode="universal">
> >         <xsl:param name="name"/>
> >         <xsl:variable name="position" select="position()"/>
> >         <xsl:element name="{$name}">
> >             <xsl:apply-templates select="../*/*[position() =
> > $position]" mode="parent">
> >                 <xsl:with-param name="name" select="@element"/>
> >             </xsl:apply-templates>
> >         </xsl:element>
> >     </xsl:template>
> >     <xsl:template match="*" mode="parent">
> >         <xsl:param name="name"/>
> >         <xsl:param name="parentName"/>
> >         <xsl:element name="{$parentName}">
> >             <xsl:apply-templates select="." mode="child">
> >                 <xsl:with-param name="name" select="$name"/>
> >             </xsl:apply-templates>
> >         </xsl:element>
> >     </xsl:template>
> >     <xsl:template match="*" mode="child">
> >         <xsl:param name="name"/>
> >         <xsl:element name="{$name}">
> >             <xsl:copy-of select="@*"/>
> >         </xsl:element>
> >     </xsl:template>
> > </xsl:stylesheet>
> >
> > =
> >
> > <?xml version="1.0" encoding="utf-8"?>
> > <sometag>
> >    <txt src="txt1.txt"/>
> >    <txt src="img1.jpg"/>
> > </sometag>
> > <sometag>
> >    <img src="txt2.txt"/>
> >    <img src="img2.jpg"/>
> > </sometag>
> >
> > This relies on the idea the child count and the parent count being
> > exactly the same.  Theres a way to write so this isn't the case but if
> > we gave you all the answers you wouldnt have any fun :)
> >
> > As such, have fun :)
> >
> >
> > On 9/28/05, Ragulf Pickaxe <ragulf.pickaxe@xxxxxxxxx> wrote:
> > > > The real problem is that I don't want to have to know anything about
> > > > <sometag>. That is, I would be free to use (and nest!) whatever
> > > > non-proprietary tag inside my <repeat>, without modifing it.
> > > > Probably there's no way in XSLT 1.0 (if it is, why creating tunnel in
> > > > 2.0 ;) , but if you see another solution...
> > > >
> > >
> > > Hi again Paolo,
> > >
> > > Why can you not have a general template for the "Sometag" and other
> > > elements that you just want to pass on?
> > >
> > > I think that your own solution would be able to provide, if you change
> > > the template that matches "Sometag" to the following:
> > >
> > > <xsl:template match="*">
> > >  <xsl:param name="index" select="1"/>
> > >  <xsl:copy>
> > >    <xsl:copy-of select="@*"/>
> > >    <xsl:apply-templates>
> > >      <xsl:with-param name="index" select="$index"/>
> > >    </xsl:apply-templates>
> > >    <!-- sometag content -->
> > >  </xsl:copy>
> > > </xsl:template>
> > >
> > > The match="ax:items" is more specific than match="*" and thus has
> > > higher priority.
> > >
> > > My solution, I think, you would have to change three templates:
> > >
> > > <xsl:template match="ax:repeat">
> > >  <xsl:apply-templates/> <!-- instead of <xsl:apply-templates
> > > select="sometag"/>-->
> > > </xsl:template>
> > >
> > > <xsl:template match="*"> <!-- Instead of <xsl:template match="sometag" -->
> > >   <xsl:copy> <!-- Copy element (shallow copy) -->
> > >     <xsl:copy-of select="@*"/> <!-- Copy all attributes -->
> > >      <!-- other non-proprietary elements to be processed: -->
> > >      <xsl:apply-templates select="*[not(self::ax:items)]"/>
> > >      <!-- Propriotary elements to be processed: -->
> > >      <xsl:apply-templates select="ax:items[1]" mode="first"/>
> > >   </xsl:copy>
> > > </xsl:template>
> > >
> > > And remove the <sometag> and </sometag>from the
> > > <xsl:template match="ax:items" mode="first">
> > > ..
> > > </
> > >
> > >
> > > Is this what you need?
> > >
> > > Regards,
> > > Ragulf Pickaxe :-)
> > >
> > >
> >
> >
> > --
> > <M:D/>
> >
> > M. David Peterson
> > http://www.xsltblog.com
> >
>
>
> --
> <M:D/>
>
> M. David Peterson
> http://www.xsltblog.com
>


--
<M:D/>

M. David Peterson
http://www.xsltblog.com

Current Thread