[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

RE: [xsl] variable as element name; issues with for-each-group


Subject: RE: [xsl] variable as element name; issues with for-each-group
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Wed, 11 Jul 2007 17:34:53 +0100

>How do I 
> filter out extra elements when any predicates added to * seem 
> to break it?

<xsl:for-each-group select="* except author">

or

<xsl:for-each-group select="*[not(self::author)]"> 

>Is 
> there a mechanism to ignore anything before the first "genus" 
> when doing the grouping? 

<xsl:for-each-group select="* except genus[1]/preceding-sibling::*)"

>I'm having trouble with current-group() and
> position() in for-each-group. Basically, nothing works.
> 
> <family name="{current-group()[1]}"> 
> 
> gives me the whole sequence when it's clear it should only 
> return the first element.

You did group-starting-with="family", so it seems likely that
current-group()[1] is a <family> element, which has a complex internal
structure. I suspect you don't want the string-value of the <family>
element, you want the value of its name attribute, that is  <family
name="{current-group()[1]/@name}"> 

> I'd like to replace
> 
> subsequence(current-group(),2) 
> 
> with something like 
> 
> subsequence(current-group(),./superfamily[1]/position())
> 
> but again it doesn't seem to work (seems to come up with no matches).

Almost certainly a context problem. If you're within for-each-group then it
seems unlikely that the context node has a child called superfamily. And
using position() on the rhs of "/" almost certainly means something
different from what you would like it to mean.

Michael Kay
http://www.saxonica.com/


> -----Original Message-----
> From: Thomas Kielczewski [mailto:thomaskiel@xxxxxxxxx] 
> Sent: 11 July 2007 16:53
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] variable as element name; issues with for-each-group
> 
> Hi,
> Please bear with me as this is a triple-shot of newbie questions.
> 
> I have the following simplified XML:
> 
> <section name="Species Accounts">
> <author>someone</author>
>   <chapter>1</chapter>
>     <superfamily>True Butterflies</superfamily>
>       <description>
>          <p>The true butterflies have antennae with rounded clubs</p>
>       </description>
>     <family>
>       <name>Swallowtails</name>
>         <description>
>           <p>The swallowtails are worldwide in distribution.</p>
>         </description>
>     </family>
>     <species>
>         <name>Cattle Heart Swallowtail</name>
>     </species>
>     <genus>
>         <name>Pipevine Swallowtails</name>
>         <description>This is a primarily tropical genus.</description>
>     </genus>
>     <species>
>         <name>Pipevine Swallowtail</name>
>     </species>
>     <species>
>         <name>Polydamas Swallowtail</name>
>     </species>
>   <chapter>2</chapter>
> ...
> </section>
> 
> 
> I am giving it this structure:
> 
> <section>
>   <chapter id="1">
>     <superfamily name="...">
>       <description/>
>       <family name="...">
>          <description/>
>          <species>...</species>
>           ...
>          <genus>
>            <species>...</species>
>           ...
>          </genus>
>           ...
>       </family>
>     <superfamily>
>   </chapter>
>   <chapter>
>   ...
>   </chapter>
> </section>
> 
> 
> This is going well, but with a few sticky issues:
> 
> 1) This is my outer for-each-group:
> 
> <xsl:for-each-group group-starting-with="chapter"
> select="*">
>   <chapter>
>   ...
>   </chapter>
> </xsl:for-each-group>
> 
> The problem is that this seems to pick up orphan elements I'd 
> rather leave alone, like "author" in the XML above, and 
> recasting them as "chapter" (complete with "id"). How do I 
> filter out extra elements when any predicates added to * seem 
> to break it?
> 
> Same idea when I group "species" under "genus", because some 
> species are not in a genus but directly under "family." Is 
> there a mechanism to ignore anything before the first "genus" 
> when doing the grouping? (This is where the higher-order 
> species will always be located.) Or is this done with some 
> crafty predicates?
> 
> 2) I'm having trouble with current-group() and
> position() in for-each-group. Basically, nothing works.
> 
> <family name="{current-group()[1]}"> 
> 
> gives me the whole sequence when it's clear it should only 
> return the first element.
> 
> Then, rather than explicitly stating the cutoff point in
> 
> <xsl:for-each-group group-starting-with="superfamily"
> select="subsequence(current-group(),2)">
> 
> I'd like to replace
> 
> subsequence(current-group(),2) 
> 
> with something like 
> 
> subsequence(current-group(),./superfamily[1]/position())
> 
> but again it doesn't seem to work (seems to come up with no matches).
> 
> 
> This is the entire XSLT:
> 
> <xsl:stylesheet
>     version="2.0"
>     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>  
>    <xsl:output
>         indent="yes"
>         method="xml" />
>     <xsl:strip-space
>         elements="*" />
> 
>     <xsl:template
>         match="section">
>         <xsl:result-document
>             href="a.xml">
> 
>             <section
>                 title="{@name}">
> 
>                 <xsl:for-each-group
>                     group-starting-with="chapter"
>                     select="*">
>                     <chapter
>                         id="{current-group()[1]}">
> 
>                         <xsl:for-each-group
>                            
> group-starting-with="superfamily"
>                            
> select="subsequence(current-group(),2)">
>                             <superfamily
>                                
> name="{current-group()[1]}">
>   
>                                 <xsl:for-each-group
>                                    
> group-starting-with="family"
>                                    
> select="subsequence(current-group(),2)">
>                                     <family
>                                        
> name="{current-group()[1]}">
>                                           
> <xsl:copy-of
>                                            
> select="following::description[1]" />
>                                         
>                                        
> <xsl:for-each-group
>                                            
> group-starting-with="genus"
>                                            
> select="subsequence(current-group(),2)">
>                                             <genus 
> name="{current-group()[1]}">
>                                                 
>                                                
> <xsl:for-each-group
>                                                    
> group-starting-with="species"
>                                                    
> select="subsequence(current-group(),2)">
>                                                     
>                                                    
> <species name="{current-group()[1]}">
>                                                       
> <xsl:copy-of select="."/>
>                                                       
> 
>                                                   
> </species>
>                                                
> </xsl:for-each-group>
>                                             </genus>
>                                         
> </xsl:for-each-group>    
>                                     </family>
>                                 </xsl:for-each-group>
>                             </superfamily>
>                         </xsl:for-each-group>
>                     </chapter>
>                 </xsl:for-each-group>
>             </section>
>          </xsl:result-document>
>      </xsl:template>
> </xsl:stylesheet>
> 
> 
> 3) Eventually, I'd like to clean up the repeating elements of 
> my template and make each level a template call using 
> parameters. But I can't even make a call to a variable work. 
> I declare my variable as a top-level element, shouldn't it be 
> visible to all? What crucial ingredient am I missing? I tried 
> this with braces and
> without:
> 
> <xsl:stylesheet
>     version="2.0"
>     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
> ...
> <xsl:variable
>         name="level2"
>         select="'superfamily'" />
> 
> <xsl:template match="section">
> ...
> <xsl:for-each-group
>                            
> group-starting-with="{$level2}"
>                            
> select="subsequence(current-group(),2)">
> <xsl:element name="{$level2}">
> <xsl:attribute name="name"
> select="current-group()[1]"/>
> ...
> </xsl:element>
> </xsl:for-each-group>
> </xsl:template>
> 
> 
> This newbie has been XSLT'ing for a little over a month now. 
> He's using Saxon 8B on <oXygen/> 8.2.  
> 
> Thanks, and congratulations for the great discussions that 
> occasionally pop up on this forum.
> 
> 
> Thomas Kielczewski
> Modality, LLC
> Durham, NC
> 
> 
>        
> ______________________________________________________________
> ______________________Ready for the edge of your seat? 
> Check out tonight's top picks on Yahoo! TV. 
> http://tv.yahoo.com/


Current Thread
Keywords
xml