This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Displaying entries in a table vertically
- To: xsl-list at lists dot mulberrytech dot com
- Subject: [xsl] Displaying entries in a table vertically
- From: Mark Nahabedian <naha at ai dot mit dot edu>
- Date: Wed, 18 Jul 2001 09:45:02 -0400 (Eastern Daylight Time)
- References: <20010717213606.82909.qmail@web14906.mail.yahoo.com>
- Reply-To: xsl-list at lists dot mulberrytech dot com
Does it matter that the entries line up horizontally?
If not, there's a simple solution: generate a table with three
columns and one row. Each cell is a table of one column and as many
rows as you need to output one third of the elements.
If that's not good enough you need to process the data in the order
that it must appear in the output rather than the order it appears in
the input.
A few months ago I was working on something similar but in my case
each element of the input had attributes which explicitly said which
row and column of the table the element should go in. I've included
the transform below in case it might be helpful. My input data looked
like
<?xml version="1.0" encoding="utf-8"?>
<!-- edited with XML Spy v3.5 NT (http://www.xmlspy.com) by Mark Nahabedian ((self)) -->
<!DOCTYPE circuit-breaker-panel [
<!ELEMENT circuit-breaker-panel (circuit-breaker)+>
<!ELEMENT circuit-breaker (amps, special?, description)>
<!ATTLIST circuit-breaker
column CDATA #REQUIRED
row CDATA #REQUIRED
height CDATA #IMPLIED
>
<!ELEMENT amps (#PCDATA)>
<!ELEMENT special (#PCDATA)>
<!ELEMENT description (#PCDATA)>
]>
<circuit-breaker-panel xmlns="http://www.ai.mit.edu/people/naha/XML-namespaces/fuse-box">
<circuit-breaker column="1" row="1" height="2">
<amps>60</amps>
<special>doubled</special>
<description>heat pump</description>
</circuit-breaker>
<circuit-breaker column="1" row="3" height="1">
<amps>15</amps>
<description>upper stairs, back bdroom stereo outlet</description>
</circuit-breaker>
<circuit-breaker column="1" row="4" height="1">
<amps>20</amps>
<description>kitchen sink garbage disposer</description>
</circuit-breaker>
<circuit-breaker column="2" row="1" height="1">
<amps>20</amps>
<special>GFCI</special>
<description>outlet of both bathrooms, back outdoor
outlets, <b>possible intermittent ground fault in
circuit</b></description>
</circuit-breaker>
<circuit-breaker column="2" row="2" height="1">
<amps>15</amps>
<description>laundry room and garage lights, lower
stairs</description>
</circuit-breaker>
<circuit-breaker column="2" row="3" height="1">
<amps>15</amps>
<description/>
</circuit-breaker>
</circuit-breaker-panel>
================================================================================
<?xml version='1.0' encoding='utf-8' ?>
<stylesheet version="1.0"
xmlns="http://www.w3.org/1999/XSL/Transform"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:fb="http://www.ai.mit.edu/people/naha/XML-namespaces/fuse-box"
exclude-result-prefixes="html svg">
<!-- Currently only 'html' is supported -->
<param name="output-type" select=" 'html' "/>
<!--
Some day need to figure out how to get this stuff in the output:
PUBLIC: "-//W3C//DTD XHTML Basic 1.0//EN"
SYSTEM: "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd"
-->
<output method="html" indent="yes" encoding="US-ASCII" standalone="no"/>
<!-- It doesn't really matter what these nodes are. We only get their positions.
They must be sequential though. This is a well known XSLT pattern.
It would be better to use nodes from the input document than from this XSLT
document because we can be sure it will have enough nodes, but I don't
know how to get its URI. It would presumably be the base URI of any input
document node.
-->
<variable name="random-nodes" select="//node()"/>
<!-- The named template cb-max-row-and-column uses this string between the two values
it returns to separate them. -->
<variable name="value-separator" select=" '---' "/>
<template match="/">
<choose>
<when test=" $output-type = 'html' ">
<html:html>
<apply-templates mode="html"/>
</html:html>
</when>
<otherwise>
<message>
<value-of select="$output-type"/>
<text>is not a supported output type.</text>
</message>
</otherwise>
</choose>
</template>
<!-- ************************* HTML specific templates ******************************** -->
<template match="fb:circuit-breaker-panel" mode="html">
<variable name="this-panel-breakers" select="fb:circuit-breaker"/>
<variable name="max-row-and-column">
<call-template name="cb-max-row-and-column">
<with-param name="circuit-breakers" select="fb:circuit-breaker"/>
</call-template>
</variable>
<variable name="MaxRows"
select="substring-before($max-row-and-column, $value-separator)"/>
<variable name="MaxColumns"
select="substring-after($max-row-and-column, $value-separator)"/>
<if test="(count($random-nodes) < $MaxRows) or
(count($random-nodes) < $MaxColumns)">
<message>
<text>Not enough random nodes. Some data will be lost in the output.</text>
</message>
</if>
<variable name="html-column-width" select="100 div $MaxColumns"/>
<variable name="html-row-height" select="100 div $MaxRows"/>
<html:table border="1">
<for-each select="$random-nodes[position() <= $MaxRows]">
<variable name="this-row" select="position()"/>
<comment>
<text>Circuit Breaker: row number </text>
<value-of select="$this-row"/>
</comment>
<html:tr height="{$html-row-height}%">
<for-each select="$random-nodes[position() <= $MaxColumns]">
<variable name="this-column" select="position()"/>
<comment>
<text> Circuit Breaker: </text>
<text>row number </text>
<value-of select="$this-row"/>
<text>, column number </text>
<value-of select="$this-column"/>
<text> </text>
</comment>
<variable name="column-breakers"
select="$this-panel-breakers[@column=$this-column]"/>
<variable name="this-circuit-breaker"
select="$column-breakers[@row=$this-row]"/>
<variable name="overlap-breakers"
select="$column-breakers[(@row < $this-row)
and (@row+@height) > $this-row]"/>
<choose>
<!-- Several circuit breakers at same location -->
<when test="(count($this-circuit-breaker) +
count($overlap-breakers))
> 1">
<message>
<text>Multiple circuit breakers at</text>
<text>row =</text>
<value-of select="$this-row"/>
<text>column =</text>
<value-of select="$this-column"/>
</message>
<comment>
<text>Multiple circuit breakers</text>
<value-of select="count($this-circuit-breaker)"/>
<text>,</text>
<value-of select="count($overlap-breakers)"/>
</comment>
</when>
<!-- No circuit breaker here but previous one in this column spans this row -->
<when test="$overlap-breakers[position() = 1]">
<comment>
<text>Previous circuit breaker colspan's this row</text>
</comment>
</when>
<!-- Display this circuit breaker -->
<when test="$this-circuit-breaker[position() = 1]">
<for-each select="$this-circuit-breaker[position() = 1]">
<html:td width="{$html-column-width}%" rowspan="{@height}">
<apply-templates select="." mode="html"/>
</html:td>
</for-each>
</when>
<!-- Empty position, placeholder cell -->
<otherwise>
<html:td bgcolor="silver">
<comment>
<text>Placeholder cell. No circuit breaker in this position.</text>
</comment>
<html:pre> </html:pre>
</html:td>
</otherwise>
</choose>
</for-each>
</html:tr>
</for-each>
</html:table>
</template>
<template match="fb:circuit-breaker" mode="html">
<html:table border="0" height="100%" width="100%">
<html:tr>
<html:th width="10%">
<value-of select="fb:amps"/>
<if test="fb:special">
<html:br/>
<value-of select="fb:special"/>
</if>
</html:th>
<html:td>
<value-of select="fb:description"/>
</html:td>
</html:tr>
</html:table>
</template>
<!-- ************************ named "subroutine" templates ******************************* -->
<!-- the named template cb-max-row-and-column looks at all of the "circuit-breaker"
elements in a given "circuit-breaker-panel" element and determines the maximum
values of the "row" and "column" attributes.
Call prototype:
<call-template name="cb-max-row-and-column">
<with-param name="circuit-breakers"/>
</call-template>
-->
<template name="cb-max-row-and-column">
<param name="previous-max-row" select="0"/>
<param name="previous-max-column" select="0"/>
<param name="circuit-breakers"/>
<choose>
<when test="boolean($circuit-breakers)">
<variable name="this-circuit-breaker"
select="$circuit-breakers[position()=1]"/>
<variable name="this-cb-last-row"
select="$this-circuit-breaker/@row +
$this-circuit-breaker/@height - 1"/>
<variable name="new-max-row">
<choose>
<when test="$this-cb-last-row > $previous-max-row">
<value-of select="$this-cb-last-row"/>
</when>
<otherwise>
<value-of select="$previous-max-row"/>
</otherwise>
</choose>
</variable>
<variable name="new-max-column">
<choose>
<when test="$this-circuit-breaker/@column > $previous-max-column">
<value-of select="$this-circuit-breaker/@column"/>
</when>
<otherwise>
<value-of select="$previous-max-column"/>
</otherwise>
</choose>
</variable>
<call-template name="cb-max-row-and-column">
<with-param name="previous-max-row"
select="$new-max-row"/>
<with-param name="previous-max-column"
select="$new-max-column"/>
<with-param name="circuit-breakers"
select="$circuit-breakers[position() > 1]"/>
</call-template>
</when>
<otherwise>
<!--
can't return multiple values as a result tree fragment because the prcessor
doesn't know how to treat such as anything other than a string.
<element name="result">
<attribute name="max-row">
<value-of select="$previous-max-row"/>
</attribute>
<attribute name="max-column">
<value-of select="$previous-max-column"/>
</attribute>
</element>
-->
<value-of select="$previous-max-row"/>
<value-of select="$value-separator"/>
<value-of select="$previous-max-column"/>
</otherwise>
</choose>
</template>
</stylesheet>
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list