RE: RE: [xsl] How to implement an array

Subject: RE: RE: [xsl] How to implement an array
From: "Michael Semcheski" <mhs-list@xxxxxxxxx>
Date: Mon, 10 Feb 2003 18:21:15 -0500
Alright, I think this could be better if I made better use of the key (but
I've never really used keys).

There are some conditions that are unhandled, such as when a month has more
than one entry for that table.

But, I think this accomplishes the stated goal of the original post.

<?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 border="1">
      <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>
		<xsl:apply-templates select="table"/> 
    </table>
  </xsl:template>

<xsl:template match="table">
	<tr>	<td>A</td>	<xsl:apply-templates select="."
mode="a-row"/>	</tr>
	<tr>	<td>B</td>	<xsl:apply-templates select="."
mode="b-row"/>	</tr>
</xsl:template>

<xsl:template match="table" mode="a-row">
	<xsl:call-template name="pr">
		<xsl:with-param name="md">A</xsl:with-param>
		<xsl:with-param name="tid" select="generate-id(.)"/>
	</xsl:call-template>
</xsl:template>

<xsl:template match="table" mode="b-row">
	<xsl:call-template name="pr">
		<xsl:with-param name="md">B</xsl:with-param>
		<xsl:with-param name="tid" select="generate-id(.)"/>
	</xsl:call-template>
</xsl:template>

<xsl:template name="pr">
	<xsl:param name="md"/>
	<xsl:param name="tid"/>
	<xsl:for-each select="../table/col">
		<xsl:sort select="@sort" data-type="number" />
		<xsl:variable name="s" select="@sort"/>
		<xsl:if test="not(following::col[@sort=$s])">
			<td>
				<xsl:for-each select="//table">
					<xsl:if test="generate-id(.)=$tid">
						<xsl:value-of
select="col[@sort=$s][@type=$md]"/>
					</xsl:if>
				</xsl:for-each>
			</td>
		</xsl:if>
	</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

-----Original Message-----
From: owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx
[mailto:owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx] On Behalf Of
cknell@xxxxxxxxxx
Sent: Monday, February 10, 2003 4:18 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: RE: RE: [xsl] How to implement an array


>> 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[@type = 'A']" mode="a-row">
    <td sort="{@sort}" month="{@month}"><xsl:value-of select="." /></td>
  </xsl:template>

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

  <xsl:template match="col[@type = 'B']" mode="a-row" />
  <xsl:template match="col[@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@xxxxxxxxxx - email


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



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


Current Thread