xsl-list
[Top] [All Lists]

Re: Grouping and sorting using an unknown node name

2002-10-07 22:12:40

--- Trem Stamp wrote:
Hi,

I have been looking on various sites for ideas on the best way to do
some
grouping/sorting, and I'm unsure of the best way to tackle it.
I've looked at the xsl:key but am not sure that this is appropriate
for
what
I'm doing.  The problem is that I have an unknown number of
element readings with unknown names (see example below), which means
I
don't
see how I can define an xsl:key.  For example, the readings
below contain Cond,TP and Turb.  The xml to be styled will vary (ie.
there
may be less than these or more with names that cannot be known
beforehand),
although all elements will have a child node called <ordinate>.

What I need to be able to do is group by the reading type (in
alphabetical
order), and for each reading type values, they need to be in date
order.

So for example the result would be:

Cond
1993-01-11         165
1993-02-10         154

TP
1993-01-11         0
1993-02-10         465

Turb
1993-01-11         0
1993-02-10         23

I'm thinking along the lines of finding out how many reading types
there are
per reading (ie. in this case 3), and then for each reading
call a template which selects the first node of each reading which
has
an
ordinate value and repeat till n. I don't know whether this is the
way
to go
about this and still not sure of how to group by date in this
instance.

Any advice would be much appreciated.

I'm using a Saxon windows binary processor

I have the following sample xml:

<Collection>
 <Group>
  <Reading>
   <Date>1993-02-10</Date>
   <SiteNumber>991001</SiteNumber>
   <Cond>
    <ordinate>154</ordinate>
   </Cond>
   <TP>
    <ordinate>465</ordinate>
   </TP>
   <Turb>
    <ordinate>23</ordinate>
   </Turb>
  </Reading>
 </Group>
 <Group>
  <Reading>
   <Date>1993-01-11</Date>
   <SiteNumber>991001</SiteNumber>
   <Cond>
    <ordinate>165</ordinate>
   </Cond>
   <TP>
    <ordinate>0</ordinate>
   </TP>
   <Turb>
    <ordinate>0</ordinate>
   </Turb>
  </Reading>
 </Group>
 ................
</Collection>

Thanks,

Trem

Hi Trem,

Here's a solution to this problem:

With your source xml:
--------------------
<Collection>
 <Group>
  <Reading>
   <Date>1993-02-10</Date>
   <SiteNumber>991001</SiteNumber>
   <Cond>
    <ordinate>154</ordinate>
   </Cond>
   <TP>
    <ordinate>465</ordinate>
   </TP>
   <Turb>
    <ordinate>23</ordinate>
   </Turb>
  </Reading>
 </Group>
 <Group>
  <Reading>
   <Date>1993-01-11</Date>
   <SiteNumber>991001</SiteNumber>
   <Cond>
    <ordinate>165</ordinate>
   </Cond>
   <TP>
    <ordinate>0</ordinate>
   </TP>
   <Turb>
    <ordinate>0</ordinate>
   </Turb>
  </Reading>
 </Group>
</Collection>


this tramsformation:
-------------------
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:vendor="urn:schemas-microsoft-com:xslt">
  
  <xsl:output method="text"/>
  
  <xsl:key name="krByName" 
           match="Reading/*[not(self::Date or self::SiteNumber)]"
           use="name()"/>
           
  <xsl:key name="krbyDate" 
           match="Date"
           use="."/>
           
  <xsl:template match="/">
   <xsl:for-each select="/*/*/Reading/*[
                                      generate-id() 
                                     = 
                                      generate-id(key('krByName',
                                                      name()
                                                      )
                                                      [1]
                                                 )
                                      ]">
     <xsl:text>&#xA;</xsl:text>
     <xsl:value-of select="name()"/>
     
     <xsl:for-each 
       select="/*/*/Reading/Date[
                               generate-id() 
                              = 
                               generate-id(key('krbyDate',
                                                .
                                               )
                                                [1]
                                           )
                               ]
                                  /following-sibling::*
                                    [name() = name(current())]">
          <xsl:sort select="preceding-sibling::Date"/>
     
     <xsl:value-of select="concat('&#xA;', 
                                  preceding-sibling::Date, 
                                  '&#9;', 
                                  .)"/>
     
     </xsl:for-each>

     <xsl:text>&#xA;</xsl:text>

   </xsl:for-each>

  </xsl:template>
</xsl:stylesheet>

when applied produces exactly the wanted result:


Cond
1993-01-11       165 
1993-02-10       154 

TP
1993-01-11       0 
1993-02-10       465 

Turb
1993-01-11       0 
1993-02-10       23 


Hope this helped.



=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL

__________________________________________________
Do you Yahoo!?
Faith Hill - Exclusive Performances, Videos & More
http://faith.yahoo.com

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



<Prev in Thread] Current Thread [Next in Thread>