xsl-list
[Top] [All Lists]

RE: [xsl] creating a head-letter for directory

2010-01-18 03:11:39
Hi Dorothy,

Based on the input file you gave... the xslt below will do exactly what
you want:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
  xmlns:fn="http://www.w3.org/2005/xpath-functions";>
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  
  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>
  
  <xsl:template match="root">
    <output>  
      <xsl:for-each-group select="data" group-by="substring(name, 1,1)">
        <letter><xsl:value-of select="current-grouping-key()"/></letter>
        <xsl:for-each select="current-group()">
          <name>
            <xsl:value-of select="name"/>
          </name>
        </xsl:for-each>
      </xsl:for-each-group> 
    </output>      
  </xsl:template>
  
  <!-- copy all nodes and attributes which are not processed by one of
available templates -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>


Cheers,
Robby Pelssers


-----Original Message-----
From: Hoskins & Gretton [mailto:hoskgret(_at_)rochester(_dot_)rr(_dot_)com] 
Sent: Monday, January 18, 2010 6:07 AM
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [xsl] creating a head-letter for directory

HI, I would like to understand, given a flat sort of data extraction, 
of the type
<?xml version="1.0" encoding="UTF-8"?>
<root>
     <data>
         <name>Aname</name>
         <!-- other elements such as <location> follow, all related 
to the <name> -->
     </data>
     <data>
         <name>Hname</name><!-- other elements such as <location> follow
-->
     </data>
     <data>
         <name>Dname</name><!-- other elements such as <location> follow
-->
     </data>
     <data>
         <name>Wname</name><!-- other elements such as <location> follow
-->
     </data>
     <data>
         <name>Anothername</name><!-- other elements such as 
<location> follow -->
     </data>
     <data>
         <name>Whatevername</name><!-- other elements such as 
<location> follow -->
     </data>
</root>

what are the groupings and keys needed to accomplish this (even 
flatter) output?

<output>
         <letter>A</etter>
         <name>Aname</name><!-- other elements such as <location> follow
-->
         <name>Anothername</name><!-- other elements such as 
<location> follow -->
         <letter>D</etter>
         <name>Dname</name><!-- other elements such as <location> follow
-->
         <letter>H</etter>
         <name>Hname</name><!-- other elements such as <location> follow
-->
         <letter>W</etter>
         <name>Wname</name><!-- other elements such as <location> follow
-->
         <name>Whatevername</name><!-- other elements such as 
<location> follow -->
<output>

I know that I first need to identify which first letters exist in the 
set of <data> elements, and then generate a <letter> element 
containing that first letter, followed by all the data elements 
children <name> that have a matching first letter. But I'm getting a 
<letter> element every time, rather than once for each unique 
occurrence, followed by the <name> elements which have a matching 
first letter. How do I generate the <letter> once, but follow it with 
all of the <name> (and related) elements? I think I need to move the 
<leter> element builder up out of the for-each  loop that it is in, 
but I don't know how I then would get each letter only once for the 
set of all <data> elements.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="2.0">
     <xsl:template match="/">
         <xsl:variable name="blocks" select="root/data"/>
         <xsl:element name="output">
             <xsl:for-each-group select="$blocks" group-by="name">
                 <xsl:sort select="current-grouping-key()"/>
                 <xsl:variable name="currentGroup" 
select="current-grouping-key()"/>
                 <xsl:variable name="headletter" 
select="substring($currentGroup,1,1)"/>
                 <xsl:for-each select="."><!-- context here should be
data -->
                     <xsl:element name="letter">
                         <xsl:value-of select="$headletter"/>
                     </xsl:element>
                     <xsl:apply-templates 
select="name[substring(.,1,1)=$headletter]"></xsl:apply-templates>
                 </xsl:for-each>
             </xsl:for-each-group>
         </xsl:element>
     </xsl:template>

     <xsl:template match="name">
         <!-- is there a way that I should use the $headletter here? -->
         <xsl:element name="name"><xsl:value-of
select="."/></xsl:element>
     </xsl:template>
</xsl:stylesheet>

output with duplicate <letter> values:
<?xml version="1.0" encoding="UTF-8"?>
<output>
         <letter>A</letter>
         <name>Aname</name>
         <letter>A</letter>
         <name>Anothername</name>
         <letter>D</letter>
         <name>Dname</name>
         <letter>H</letter>
         <name>Hname</name>
         <letter>W</letter>
         <name>Whatevername</name>
         <letter>W</letter>
         <name>Wname</name>
</output>

Regards, Dorothy 


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

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