xsl-list
[Top] [All Lists]

Re: [xsl] using xsl:for-each-group, grouping by child nodes?

2008-10-05 10:06:20
On 5/10/08 7:48 AM, "G. Ken Holman" <gkholman(_at_)CraneSoftwrights(_dot_)com> 
wrote:

Then use XSLT 1.0 to solve the problem ... no reason to give up.

I hope the below helps.

Thanks for this, I was all set to pre-process it inside the database and
export munged data (eg. flag fields indicating group starts). I really
appreciate your help here.

OK, this almost works for me - the xml I posted to the list was a bit
simplified and I must be screwing up the last bit of retrofitting. The
actual full XML is this:

<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult";>
<ERRORCODE>0</ERRORCODE>
<PRODUCT BUILD="06-20-2006" NAME="FileMaker Pro" VERSION="8.5v1"/>
<DATABASE DATEFORMAT="D/m/yyyy" LAYOUT="" NAME="x-nested-muenchian-test.fp7"
RECORDS="6" TIMEFORMAT="h:mm:ss a"/>
<METADATA>
    <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="name" TYPE="TEXT"/>
    <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="number" TYPE="TEXT"/>
    <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="position" TYPE="TEXT"/>
    <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="state" TYPE="TEXT"/>
    <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="team" TYPE="TEXT"/>
</METADATA>
<RESULTSET FOUND="6">
     <ROW MODID="3" RECORDID="1">
         <COL><DATA>joe</DATA></COL>
         <COL><DATA>2</DATA></COL>
         <COL><DATA>pitcher</DATA></COL>
         <COL><DATA>ny</DATA></COL>
         <COL><DATA>mets</DATA></COL>
     </ROW>
     <ROW MODID="3" RECORDID="2">
         <COL><DATA>mark</DATA></COL>
         <COL><DATA>11</DATA></COL>
         <COL><DATA>outfielder</DATA></COL>
         <COL><DATA>ny</DATA></COL>
         <COL><DATA>mets</DATA></COL>
     </ROW>
     <ROW MODID="3" RECORDID="3">
         <COL><DATA>jane</DATA></COL>
         <COL><DATA>13</DATA></COL>
         <COL><DATA>outfielder</DATA></COL>
         <COL><DATA>ny</DATA></COL>
         <COL><DATA>cubs</DATA></COL>
     </ROW>
     <ROW MODID="3" RECORDID="4">
         <COL><DATA>mike</DATA></COL>
         <COL><DATA>7</DATA></COL>
         <COL><DATA>outfielder</DATA></COL>
         <COL><DATA>ny</DATA></COL>
         <COL><DATA>mets</DATA></COL>
     </ROW>
</RESULTSET>
</FMPXMLRESULT>

So I thought the code needed to be tweaked like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
    version="1.1"
    xmlns:fmp="http://www.filemaker.com/fmpxmlresult";
    exclude-result-prefixes='fmp'
    >
<xsl:output 
    method="text" 
    version="1.0" 
    encoding="UTF-8" />

<xsl:template match="/fmp:FMPXMLESULT">
   <!--group first by team; using a key of two parts with an unlikely
       character in between to avoid any ambiguous concatenations-->
   <xsl:variable name="players" select="/fmp:FMPXMLESULT/*/fmp:ROW"/>
   <xsl:for-each select="$players">
     <xsl:if test="generate-id(.)=
        generate-id($players[concat(
            fmp:COL[4]/fmp:DATA,'&#xd;',fmp:COL[5]/fmp:DATA)=
               concat(current()/fmp:COL[4]/fmp:DATA, '&#xd;',
                      current()/fmp:COL[5]/fmp:DATA)][1])">
       <!--found the first player for a given team-->
       <xsl:if test="generate-id(.)!=generate-id($players[1])">
         <xsl:text>&#xa;</xsl:text>
       </xsl:if>
       <xsl:text>&#xa;    Team: </xsl:text>
       <xsl:value-of select="concat(fmp:COL[5]/fmp:DATA,',
            ',fmp:COL[4]/fmp:DATA)"/>
       <xsl:variable name="team"
            select="$players[concat(fmp:COL[4]/fmp:DATA, '&#xd;',
                fmp:COL[5]/fmp:DATA) = concat(
                  current()/fmp:COL[4]/fmp:DATA, '&#xd;',
                  current()/fmp:COL[5]/fmp:DATA)]"/>
       <!--now group by position; reflecting plural where applicable-->
       <xsl:for-each select="$team">
         <xsl:if test="generate-id(.) =
                  generate-id($team[fmp:COL[3]/fmp:DATA =
                               current()/fmp:COL[3]/fmp:DATA][1])">
           <xsl:text>&#xa;       </xsl:text>
           <xsl:value-of select="fmp:COL[3]/fmp:DATA"/>
           <xsl:variable name="position"
                select="$team[fmp:COL[3]/fmp:DATA =
                         current()/fmp:COL[3]/fmp:DATA]"/>
           <xsl:if test="count($position)>1">s</xsl:if>:<xsl:text/>
           <!--show all in the position-->
           <xsl:for-each select="$position">
             <xsl:text>&#xa;           </xsl:text>
             <xsl:value-of
                  select="concat(fmp:COL[1]/fmp:DATA,',
                                 ',fmp:COL[2]/fmp:DATA)"/>
           </xsl:for-each>
         </xsl:if>
       </xsl:for-each>
     </xsl:if>
   </xsl:for-each>
</xsl:template>

(btw, is there any short-hand way to avoid having to specify the ?fmp¹
prefix everywhere like this?)

but I¹m getting the wrong output:

0joe2pitchernymetsmark11outfieldernymetsjohn23pitchernymetspete27outfieldern
ycubsroy13outfieldernycubscarl32infieldernycubs

My eyes are tired ­ I probably did something stupid.

I see you run training courses .. are you thinking of coming to Sydney
anytime soon?

e.


--~------------------------------------------------------------------
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>
--~--