[xsl] to generate <table columns> with widths using a "lookup-table/list/array in the xsl" for a customizable XSL-FO & XSL-HTML

Subject: [xsl] to generate <table columns> with widths using a "lookup-table/list/array in the xsl" for a customizable XSL-FO & XSL-HTML
From: "SANWAL, ABHISHEK (HP-Houston)" <abhishek.sanwal@xxxxxx>
Date: Fri, 17 Oct 2003 14:48:03 -0500
PROBLEM SUMMARIZED DESCRIPTION:
To generate <fo:table-column> and <col> tags for tabular data where the
count is retrieved from the incoming XML Data and the column widths are
obtained from the XSL and at the same time restrict those column widths
to that particular section only. 

- Long interesting problem - If it needs more explanation please let me
know. Meanwhile I "think" (maybe I am wrong) that I've detailed it out
well enough :).

DETAILS & NITTY GRITTIES:

The following files come into the picture:
1. Big.xsl (Has sections & section parameters) - encompasses all the
functional XSL modules
2. Matrix.xsl ( is one of the functional modules used & called/applied
to by Big.xsl. It applies to MATRIX elements in the data and is
customizable/configurable from Big.xsl, included by the Big.xsl )

(Samples for testing and seeing it work to some extent)
3. Sample Data File : MatrixTest.xml 
4. Sample XSL File: MatrixTest.xsl <- A stand alone version of
Matrix.xsl 
(of course matrix.xsl retrives parameters)

I am trying to maintain a strong separation between content and
styling/layout information.

**********
MatrixTest.xml
**********
<?xml version="1.0" encoding="UTF-8"?>
<root>

<Matrix HeadFlow="Vertical" HeadExists="1" HeadCount="4" DataCount="1">
<MatrixHeadArray j="0">
	<MatrixHeadCell i="1">Standard </MatrixHeadCell>
	<MatrixHeadCell i="2">Maximum </MatrixHeadCell>
	<MatrixHeadCell i="3">Standard </MatrixHeadCell>
	<MatrixHeadCell i="4">Maximum </MatrixHeadCell>
</MatrixHeadArray> <MatrixDataArray j="1">
	<MatrixDataCell i="1" j="1">Data1</MatrixDataCell>
	<MatrixDataCell i="2" j="1">32GB</MatrixDataCell>
	<MatrixDataCell i="3" j="1">Data2</MatrixDataCell>
	<MatrixDataCell i="4" j="1">32GB</MatrixDataCell>
</MatrixDataArray> </Matrix>

<Matrix HeadFlow="Horizontal" HeadExists="1" HeadCount="3"
DataCount="2"> <MatrixHeadArray j="0">
	<MatrixHeadCell i="1">Slot Type:</MatrixHeadCell>
	<MatrixHeadCell i="2"/>
	<MatrixHeadCell i="3">Voltage:</MatrixHeadCell>
</MatrixHeadArray> <MatrixDataArray j="1">
	<MatrixDataCell i="1" j="1">64-bit, 100-MHz PCI Hot
Plug</MatrixDataCell>
	<MatrixDataCell i="2" j="1">4, 4 available</MatrixDataCell>
	<MatrixDataCell i="3" j="1">3.3 Volt Only</MatrixDataCell>
</MatrixDataArray> <MatrixDataArray j="2">
	<MatrixDataCell i="1" j="2">64-bit, 100-MHz PCI Non-Hot
Plug</MatrixDataCell>
	<MatrixDataCell i="2" j="2">3, 3 available</MatrixDataCell>
	<MatrixDataCell i="3" j="2">5 Volt or 3.3 Volt</MatrixDataCell>
</MatrixDataArray> </Matrix>

</root>

***************
MatrixTest.xsl  (Please note the sections marked important)
****************
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                version="1.0">

  <xsl:output method="xml" encoding="iso-8859-1"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>
          <xsl:text>Horizontal and Vertical Tables</xsl:text>
        </title>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="Matrix">
    
    <xsl:if test="contains(@HeadFlow,'H')">
      <h3>Horizontal</h3>

      <table border="0">

<!-- IMPORTANT SECTION START -->
<!-- Here I am using a variable to iterate through the columns and
generate the number of columns required and the number "i" of each
column

There is difference between the XML DATA(Content) and the Styling
VALUES/NUMBERS that I am using copy these XML/XSL into files, uncomment
stuff and read & execute it.

The reason I am generating these <fo:table-columns> based on the COUNT
of the XML Data is that XSL:FO requires number of cols & their widths to
render a FO:table (irrespective of the problem at hand)

I have been able to generate the columns. 
But I want to be able to retrieve the WIDTHS from a particular
restricted area in Big.xsl ( I shall explain that below with comments in
BigXSL)
-->

<xsl:for-each select="MatrixHeadArray/MatrixHeadCell">

<xsl:variable name="coliterator">
	<xsl:value-of select="@i"/>
</xsl:variable>

<p><xsl:text>value of coliterator:</xsl:text><xsl:value-of
select="$coliterator"></xsl:value-of></p>
<!-- <fo:table-column column-number="{$coliterator}" column-width=""/>
-->

</xsl:for-each>

<!-- IMPORTANT SECTION END -->

        <xsl:apply-templates mode="H"/>
      </table>
    </xsl:if>
    
    <xsl:if test="contains(@HeadFlow,'V')">
      <h3>Vertical</h3>

      <table border="0">

<!-- IMPORTANT SECTION 2 START -->

<xsl:for-each select="(MatrixHeadArray|MatrixDataArray)">

	<xsl:variable name="coliterator">
		<xsl:value-of select="@j+1"/>
	</xsl:variable>

<p><xsl:text>value of coliterator:</xsl:text><xsl:value-of
select="$coliterator"></xsl:value-of></p>	
<!-- <fo:table-column column-number="{$coliterator}" column-width=""/>
-->

</xsl:for-each>

<!-- IMPORTANT SECTION 2 END -->

        <xsl:apply-templates mode="V"/>
      </table>
    </xsl:if>
  
  </xsl:template>

  <xsl:template match="MatrixHeadArray" mode="H">
    <tr>
      <xsl:apply-templates mode="H"/>
    </tr>
  </xsl:template>

  <xsl:template match="MatrixHeadCell" mode="H">
    <th>
      <xsl:apply-templates/>
    </th>
  </xsl:template>

  <xsl:template match="MatrixDataArray" mode="H">
    <tr>
      <xsl:apply-templates mode="H"/>
    </tr>
  </xsl:template>

  <xsl:template match="MatrixDataCell" mode="H">
    <td>
      <xsl:apply-templates/>
    </td>
  </xsl:template>

  <xsl:template match="MatrixHeadArray" mode="V">
    <xsl:for-each select="MatrixHeadCell">
      <tr>
        <th>
          <xsl:apply-templates/>
        </th>
        <xsl:variable name="headloc">
          <xsl:value-of select="@i"/>
        </xsl:variable>
        <xsl:for-each select="../../MatrixDataArray">
          <td>
            <xsl:apply-templates select="MatrixDataCell[@i=$headloc]"/>
          </td>
        </xsl:for-each>
      </tr>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="MatrixDataCell" mode="V"/>

</xsl:stylesheet>

*********
Big.XSL
********

This xsl is responsible for defining parameters/tweaks for the
individual sections of the result document (HTML & PDF).

For e.g. it uses several matching templates of the following type and
passes parameters to define the customized application of the other
smaller functional XSLs (just like Matrix.xsl ) to the xml data. 

This makes integrating and customizing (without hardcoding) individual
sections with their individual needs.

I am pushing out a lot of these parameters.

Now I want to be able to key-in the column-widths for the MATRIX/TABLEs
that are going to be in this section, but I want to be able to key them
into this AREA of the Big XSL.

They may or may not be parameters, variables or another name space. But
they need to be applied and retrieved only for this SECTION of the data.

The reason I want THESE COLUMN WIDTH VALUES TO BE (PHYSICALLY) here
within the section:

1. So that any person or junior developer or person can tweak the column
widths and not have to worry or understand anything but VALUES and
CERTAIN things (like all other parameters).

2. It will be easy to maintain.

Please look below in the section marked MATRIX DATA

e.g.

...
<xsl:template match="Section[@SectionHeading='MySectionName1']">
	<xsl:apply-templates select="." mode="two">
....(parameters etc.) 
	</xsl:apply-templates>
</xsl:template>

<xsl:template match="Section[@SectionHeading='MySectionName2']">
	<xsl:apply-templates select="." mode="two">

		<!-- Layout Selection - Parameters -->
		<xsl:with-param name="SectionLayout" select="'2C'"/>
		<xsl:with-param name="ParagraphLayout" select="'1C'"/>
		<xsl:with-param name="ParaItemLayout" select="'1C'"/>
		<xsl:with-param name="ImageLayout" select="'XC'"/>


		<!-- Section - Parameters -->
		
		<xsl:with-param name="SWidth" select="'720'"/>
		<xsl:with-param name="SHWidth" select="'150'"/>
		<xsl:with-param name="SHNWidth" select="''"/>
		<xsl:with-param name="SBWidth" select="''"/>
		<xsl:with-param name="SBNWidth" select="''"/>

		<!-- Paragraph - Parameters -->

		<xsl:with-param name="PWidth" select="'100%'"/>
		<xsl:with-param name="PHWidth" select="''"/>
		
		<xsl:with-param name="PIWidth" select="''"/>
		<xsl:with-param name="SIWidth" select="''"/>

		<xsl:with-param name="PIBullet" select="''"/>
		<xsl:with-param name="SIBullet" select="''"/>

		<!--	 Matrix - Parameters  -->
		<xsl:with-param name="MWidth" select="''"/>

		<!-- Matrix Head -->
		<xsl:with-param name="MC0Width" select="''"/>

		<!-- Matrix Data -->
<!-- THIS IS THE "kind of" INFORMATION THAT NEEDS TO BE RETRIEVED BY
Matrix.xsl when applied to the Xml Data and it preferably remains within
the bounds of this Section Matching template.

QUESTION IS: How can I modify the current Matrix.xsl ( basically
MatrixTest.xsl), BigXsl and be able to have it pick up/use the column
count from the XML Data (MatrixTest.xml) and pick up styling information
(column widths) from the Big.XSL ?

		<xsl:with-param name="MCAllWidth" select="''"/>
		<xsl:with-param name="MC1Width" select="''"/>
		<xsl:with-param name="MC2Width" select="''"/>
		<xsl:with-param name="MC3Width" select="''"/>
		<xsl:with-param name="MC4Width" select="''"/>
		<xsl:with-param name="MC5Width" select="''"/>

		<!-- Matrix Head and Data Alignment -->
		<xsl:with-param name="HeadAlign" select="'Center'"/>
		<xsl:with-param name="DataAlign" select="'Left'"/>


		<!-- Image Layout Frame - Parameters -->
		<xsl:with-param name="ImageWidth" select="''"/>
		<xsl:with-param name="ImageHeight" select="''"/>
		<xsl:with-param name="CalloutWidth" select="''"/>
		<xsl:with-param name="CalloutHeight" select="''"/>

	</xsl:apply-templates>
</xsl:template>

...
<xsl:template match="Section[@SectionHeading='MySectionName3']">
	<xsl:apply-templates select="." mode="two">
....(parameters etc.) 
	</xsl:apply-templates>
</xsl:template>

I will at the same time be trying out possibilities with the previous
samples that were posted to this subject by Wendell and Dimitre.


Abhishek Sanwal
HP - Houston Campus
abhishek.sanwal@xxxxxx

-----Original Message-----
From: Wendell Piez [mailto:wapiez@xxxxxxxxxxxxxxxx] 
Sent: Monday, September 15, 2003 11:17 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: RE: [xsl] Re: whats the best way to create and use values for
lookup (key-value) such that you can loop through it with limits

Abhishek,

For reasons explained by Ken, I don't think your solution will work the
way 
you are describing; but I'm not sure you need the control over the scope
of 
variables you say you require.....

At 08:58 PM 9/13/2003, you wrote:
>Now my document has various chapters which have various sections where
a
>given section can have any number of matrices (matrix) and/or 
>paragraphs.
>
>Now in the XSL for this I need to be able to HARD-CODE certain values 
>INTO A SECTION  that are to be used by all INNER TEMPLATES (namely, 
>Matrix, Paragraph, Items, SubItems etc.) ( But are NOT accessible to 
>other section matches

By this, do you mean hard-code these values into your source document,
or 
into your stylesheet?

If into your source document, then each section would contain a
particular 
set of nodes providing the parameters you want. So a section could look
like:

<section SectionHeading='MySectionSomething1'>
<table-params>
   <col which="MC1Width">30</col>
   <col which="MC2Width">40</col>
   <col which="MC3Width">25</col>
   <col which="MC4Width">50</col>
   <col which="MC5Width">70</col>
</table-params>

Then in your stylesheet, the values are accessible from any template,
given 
an XPath. So inside a table, you could always retrieve 
ancestor::section[1]/table-params/col[@which=$colName] ... or you can
first 
bind ancestor::section/table-params/col to a variable colSpecs and then
ask 
for $colSpecs[@which=$colName]....

If you want these values to be in the stylesheet, then use the lookup
table 
technique Dimitre demonstrated....

<my:table-specs>
   <section SectionHeading='MySectionSomething1'>
     <col which="MC1Width">30</col>
     <col which="MC2Width">40</col>
     <col which="MC3Width">25</col>
     <col which="MC4Width">50</col>
     <col which="MC5Width">70</col>
   </section>
   <section SectionHeading='MySectionSomething2'>
     ....
   </section>
</my:table-specs>

Binding my:table-specs to a variable

<xsl:variable name="table-specs"
select="document('')/*/my:table-specs"/>

You can always say

$table-specs[@SectionHeading=current()/ancestor::Section[@SectionHeading
]/col[@which=$colName]

I hope that helps. Many times "parameterizing" something in XSLT doesn't

actually require formal parameters or variables -- it's just retrieving 
node values (but those values have to be in a tree somewhere, or
calculable).

Cheers,
Wendell


======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
   Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


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


 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