xsl-list
[Top] [All Lists]

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

2004-05-25 05:33:35

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