RE: [xsl] This could be simple, but not for me!

Subject: RE: [xsl] This could be simple, but not for me!
From: "Andrew Welch" <ajwelch@xxxxxxxxxxxxxxx>
Date: Tue, 25 May 2004 13:33:35 +0100
> Hi,
> 
> Though I have been working sometime with XSLT, I am having 
> trouble with this transformation. Anyone know how to do this? 
> The XML source is from a database and is really really huge 
> in size, so performance of the transformation is very critical...
> 
> 
> <Root>
>     <Community>
>         <City>City1</City>
>         <A>
>             <B>
>                 <Name>Name1</Name>
>                 <Info>
>                     <Detail no="100">Red</Detail>
>                 </Info>
>             </B>
>             <B>
>                 <Name>Name2</Name>
>                 <Info>
>                     <Detail no="200">Blue</Detail>
>                 </Info>
>             </B>
>             <B>
>                 <Name>Name3</Name>
>                 <Info>
>                     <Detail no="300">Green</Detail>
>                 </Info>
>             </B>
>         </A>
>     </Community>
>     <Community>
>         <City>City2</City>
>         <A>
>             <B>
>                 <Name>Name4</Name>
>                 <Info>
>                     <Detail no="100">Red</Detail>
>                 </Info>
>             </B>
>             <B>
>                 <Name>Name5</Name>
>                 <Info>
>                     <Detail no="200">Blue</Detail>
>                 </Info>
>             </B>
>             <B>
>                 <Name>Name6</Name>
>                 <Info>
>                     <Detail no="400">Yellow</Detail>
>                 </Info>
>             </B>
>         </A>
>     </Community>
> </Root>
> 
> 
> This is the result I need to produce:
> 
> 
> 100, Red
> 
>     City1
>         Name1
>     
>     City2
>         Name4
>     
>     
> 200, Blue
> 
>     City1
>         Name2
>         
>     City2
>         Name5
>         
> 300, Green
> 
>     City1
>         Name3
>         
> 400, Yellow
> 
>     City2
>         Name6

Heres a stylesheet that will do it.  It's a grouping problem, you just
need to group <Detail> elements by their id attibute and text content,
then apply templates to only the first one in the group.  Check out
jeni's site for more on grouping http://www.jenitennison.com

(I've html like tags in the output rather than whitespace so my IDE can
tidy it for me :) You may want to replace the ancestor:: use with
another key to help performance)

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:key name="details" match="Detail" use="concat(@no,'/',.)"/>

<xsl:template match="/">
  <root>
    <xsl:apply-templates select="//Detail[generate-id() =
generate-id(key('details',concat(@no,'/',.))[1])]"/>
  </root>
</xsl:template>

<xsl:template match="Detail">
  <div detail="{concat(@no,', ',.)}">
    <xsl:for-each select="key('details',concat(@no,'/',.))">
      <span>
        <xsl:value-of select="ancestor::Community/City"/>,<xsl:text/>
        <xsl:value-of select="parent::Info/preceding-sibling::Name"/>
      </span>
  </xsl:for-each>
  </div>
</xsl:template>

</xsl:stylesheet>


cheers
andrew

Current Thread