xsl-list
[Top] [All Lists]

RE: RE: How to implement an array

2003-02-10 14:18:20
Do I understand that you have an element which will
contain child elements, each of which you wish to
use as the heading values for a table?

If that is right, is it also correct that you will
have one or more instances of the parent element,
but that the child elements are optional? That is to
say that all possible child elements will not
necessarily appear in all instances of the parent
element.

If these things are true, then we have two problems
to solve:
1) collect all possible values for column names
2) construct a table with one column for each column
name

Is this correct?
-- 

Charles, that is correct. I can implement it without
arrays...but the solution is very large and not very
elegant. I was hoping xsl provide a more elegant way.

Imrran

I was hoping someone would else would come forward, but since no one else has 
taken me off the hook, I'd like to report my progress in the hope that someone 
will add the missing piece to complete this puzzle.

Consider this XML data document which I believe matches the description you 
gave:
===========================================================

<?xml version="1.0" encoding="UTF-8" ?>
<group>
  <table>
    <col sort="4" month="Apr" type="A">20</col>
    <col sort="5" month="May" type="A">25</col>
    <col sort="6" month="Jun" type="A">30</col>
    <col sort="10" month="Oct" type="B">35</col>
    <col sort="1" month="Jan" type="A">5</col>
    <col sort="2" month="Feb" type="A">10</col>
    <col sort="3" month="Mar" type="A">15</col>
    <col sort="11" month="Nov" type="B">40</col>
    <col sort="12" month="Dec" type="B">45</col>
  </table>
  <table>
    <col sort="8" month="Aug" type="A">70</col>
    <col sort="9" month="Sep" type="A">75</col>
    <col sort="10" month="Oct" type="A">80</col>
    <col sort="11" month="Nov" type="A">85</col>
    <col sort="4" month="Apr" type="B">50</col>
    <col sort="5" month="May" type="B">55</col>
    <col sort="6" month="Jun" type="B">60</col>
    <col sort="7" month="Jul" type="A">65</col>
    <col sort="12" month="Dec" type="A">90</col>
  </table>
</group>


When processed with this stylesheet, we are nearly there:
=========================================================
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
  <xsl:output method="html" indent="yes" encoding="UTF-8" />
  <xsl:strip-space elements="*" />
  <xsl:key name="union" match="group/table/col" use="@month" />

  <xsl:template match="/">
    <xsl:apply-templates mode="html-table" />
  </xsl:template>

  <xsl:template match="group" mode="html-table">
    <table>
      <tr><td></td>
      <xsl:for-each select="table/col[count(.|key('union', @month)[1]) = 1]">
        <xsl:sort select="@sort" data-type="number" />
        <td><xsl:value-of select="@month" /></td>
      </xsl:for-each>
      </tr>
      <tr>
      <td>A</td>
        <xsl:apply-templates select="table/col" mode="a-row">
          <xsl:sort select="@sort" data-type="number" />
        </xsl:apply-templates>
      </tr>

      <tr><td>B</td>
        <xsl:apply-templates select="table/col" mode="b-row">
          <xsl:sort select="@sort" data-type="number" />
        </xsl:apply-templates>
      </tr>
    </table>
  </xsl:template>

  <xsl:template match="table/col[(_at_)type = 'A']" mode="a-row">
    <td sort="{(_at_)sort}" month="{(_at_)month}"><xsl:value-of select="." 
/></td>
  </xsl:template>

  <xsl:template match="table/col[(_at_)type = 'B']" mode="b-row">
    <td sort="{(_at_)sort}" month="{(_at_)month}"><xsl:value-of select="." 
/></td>
  </xsl:template>

  <xsl:template match="col[(_at_)type = 'B']" mode="a-row" />
  <xsl:template match="col[(_at_)type = 'A']" mode="b-row" />

</xsl:stylesheet>


The output:
=========================================================
<table>
  <tr>
    <td></td>
    <td>Jan</td>
    <td>Feb</td>
    <td>Mar</td>
    <td>Apr</td>
    <td>May</td>
    <td>Jun</td>
    <td>Jul</td>
    <td>Aug</td>
    <td>Sep</td>
    <td>Oct</td>
    <td>Nov</td>
    <td>Dec</td>
  </tr>
  <tr>
    <td>A</td>
    <td sort="1" month="Jan">5</td>
    <td sort="2" month="Feb">10</td>
    <td sort="3" month="Mar">15</td>
    <td sort="4" month="Apr">20</td>
    <td sort="5" month="May">25</td>
    <td sort="6" month="Jun">30</td>
    <td sort="7" month="Jul">65</td>
    <td sort="8" month="Aug">70</td>
    <td sort="9" month="Sep">75</td>
    <td sort="10" month="Oct">80</td>
    <td sort="11" month="Nov">85</td>
    <td sort="12" month="Dec">90</td>
  </tr>
    <tr><td>B</td>
    <td sort="4" month="Apr">50</td>
    <td sort="5" month="May">55</td>
    <td sort="6" month="Jun">60</td>
    <td sort="10" month="Oct">35</td>
    <td sort="11" month="Nov">40</td>
    <td sort="12" month="Dec">45</td>
  </tr>
</table>


Generating a list of unique month names was easy to do using the <xsl:key> 
element and the key() function. I am stuck, probably at the same spot you are, 
at how to get empty <td> elements in the columns at the rows where there is no 
corresponding <col> element. I believe that what is called for is a template 
which will match when there is no <col> element with the appropriate "type" 
attribute that will insert the empty <td> element. But several hours of 
experimentation have not yielded an answer. I suspect that one of the list 
heavyweights can spot the solution at a glance. It is my hope that one of them 
will carry this the last part of the way.
-- 
Charles Knell
cknell(_at_)onebox(_dot_)com - email


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list