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

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


Subject: [xsl] variable as element name; issues with for-each-group
From: Thomas Kielczewski <thomaskiel@xxxxxxxxx>
Date: Wed, 11 Jul 2007 08:53:07 -0700 (PDT)

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