[xsl] howto convert node set into 2D table

Subject: [xsl] howto convert node set into 2D table
From: "Sam Carleton" <scarleton@xxxxxxxxxxxxxxxx>
Date: Wed, 4 Jul 2007 00:33:47 -0400
Ok folks,

As I work more on this XSLT, it keeps getting more complex!  I took
jingjun advice on how to add the empty rows and it works great.  The
problem is I forgot something...

There is an attribute to determine if the element should be shown, the
data really looks like this:

<category>
<images>
  <image name="a" display="true">1</image>
  <image name="b" display="true">2</image>
  <image name="c" display="true">3</image>
  <image name="d" display="true">4</image>
  <image name="e" display="false">5</image>
  <image name="f" display="true">6</image>
  <image name="g" display="false">7</image>
  <image name="h" display="true">8</image>
</images>
</category>

And here is the XSLT that displays everything, ignoring the display attribute:

 <xsl:template match="images">
   <table border="3">

     <xsl:for-each select="image[position() mod 5 = 1]">
       <xsl:text>&#10;</xsl:text>
       <tr>
         <xsl:for-each select=".|following-sibling::image[position() &lt; 5]">
           <td>
             <xsl:value-of select="concat(@name,':',.)"/>
           </td>
         </xsl:for-each>
         <xsl:call-template name="gen_blank_table_col">
           <xsl:with-param name="col_num">
             <xsl:value-of select="5 -
(count(.|following-sibling::image[position() &lt; 5]))"/>
           </xsl:with-param>
         </xsl:call-template>
       </tr>
     </xsl:for-each>

     <xsl:text>&#10;</xsl:text>
   </table>
 </xsl:template>
 <!-- =======================================================================
-->
 <!-- This template is used to generate blank table col.-->
 <!--=======================================================================
-->
 <xsl:template name="gen_blank_table_col">
   <xsl:param name="col_num"/>
   <xsl:if test="$col_num > 0">
     <td> - </td>
     <xsl:call-template name="gen_blank_table_col">
       <xsl:with-param name="col_num">
         <xsl:value-of select="$col_num - 1"/>
       </xsl:with-param>
     </xsl:call-template>
   </xsl:if>
 </xsl:template>

My first though is that before the the first for-each, I need to
create a temporary node set of all the image elements that have the
display attribute set to true.  The question is how?  Let me throw in
one more issue...

The data is a bit more complex then the sample data above.  The
<category> element can also contain a <categories> element that
contains another set of <category> elements.  I need to transform both
the images/image and the categories/category under the main category
element, the same way.

Ok, after writing this out, I think I know what I should be doing:

1: At the top <category> element, go off and create a new temporary
node set of either all the images/image[@display='true'] |
categories/category[@display='true']
2: Turn the <xsl:template match="images"> into a named template and
pass it the temporary node set from #1

The biggest problem I am having is that in all the for-each, it
directly refers to the image element, how do I consistently refer to
either the image or the category element?  I would like to stick with
on and run with it through out.  The first thing that pops to mind is
rather then simply copying the whole node in #1, copy the key data
from either the image or category elements into a new element so that
in #2, the element name is always the same.

Any thoughts on all my rambling?  Can you tell it is 12:30am my time
and I am tired;)  I am off to bed!  Thanks in advance for any and all
help!

Sam

Current Thread