Re: [xsl] Is this a legal XPath Expression?

Subject: Re: [xsl] Is this a legal XPath Expression?
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Thu, 15 Mar 2001 13:08:21 +0000
Hi Phil,

> Basically what I am doing is TRying to find unique occurrences of
> the contents of cells in column 15 of an HTML table, e.g
> , then, for each of these, pick out unique occurrences of the
> contents of cells in column 28, and for each of those, pick out the
> contents of cell 3. Looks like a job for <saxon:group>, but I
> couldn't figure out how to do it, so my code looks like this: (it
> works, but its v. inefficient!)

I'd use keys for this (i.e. the Muenchian Method), and index each
*row* according to:

  (a) column 15
  (b) column 15 + column 28
  (c) column 15 + column 28 + column 3

The three keys would be:

<xsl:key name="group-15"      match="TR"
         use="TD[15]" />
<xsl:key name="group-15-28"   match="TR"
         use="concat(TD[15], '::', TD[28])" />
<xsl:key name="group-15-28-3" match="TR"
         use="concat(TD[15], '::', TD[28], '::', TD[3])" />

Now you should apply templates to only the unique rows. In the first
go, those are the rows where they're the first node in the list
returned when you use the 'group-15' key with a value of their own
TD[15] child.  So apply templates with:

   select="TR[count(.|key('group-15', TD[15])[1]) = 1]"
   mode="group-15" />

The count() expression counts how many nodes there are in the node set
consisting of (a) the TR element you're looking at and (b) the first
of the nodes returned by the 'group-15' key when you use an index
value of the TR element that you're looking at's TD[15] child.

Then you can have a template that matches the TR elements in
'group-15' mode.  This template will only ever be applied to the
TR elements with unique values for their TD[15] child, so you don't
have to worry about testing the TR element for uniqueness.  Here, you
apply templates according to the second grouping in a very similar way
to how it's done above.

<xsl:template match="TR" mode="group-15">
   <xsl:variable name="subject" select="TD[15]" />
   <xsl:if test="string($subject)">
      <xsl:variable name="link" select="generate-id($subject)"/>
            <a href="{$link}.html"><xsl:value-of select="$subject"/></a>
      <!-- for each subject, output the project title to a sep. file-->
      <saxon:output file="{concat($link, '.html')}">
                                            concat($subject, '::', TD[28])[1]) = 1]"
                   mode="group-15-28" />

Then you have another template that matches TR elements but in
group-15-28 mode.  Again it applies templates to the uniquely valued
table rows only:

<xsl:template match="TR" mode="group-15-28">
   <xsl:variable name="subject" select="TD[3]" />
   <xsl:variable name="projecttitle" select="TD[28]" />
   <xsl:if test="string($projecttitle)">
      <xsl:variable name="link" select="generate-id($projecttitle)" />
            <a href="{$link}.html"><xsl:value-of select="$projecttitle"/></a>

      <!-- for each project, output the filename to a sep. file-->
      <saxon:output file="{concat($link, '.html')}">
                                          concat($subject, '::',
                                                 $projecttitle, '::',
                                                 TD[3])[1]) = 1]"
                   mode="group-15-28-3" />


And finally a template that matches in group-15-28-3 mode:

<xsl:template match="TR" mode="group-15-28-3">
   <xsl:variable name="fn"  select="TD[3]"/>
         <a href="{$fn}">Download <xsl:value-of select="$fn"/></a>

This is untested as I didn't have a sample.  But I think it should
roughly work.

I hope that helps,


Jeni Tennison

 XSL-List info and archive:

Current Thread