Tables

Tables can be very complicated, both in describing all the table elements and attributes accurately in the XML file and in creating an efficient XSL file to transform and display the XML table as XHTML. Varying column widths, column spans, row spans, and background colors in cells present additional challenges to establishing a universal XML format and XSL templates for all tables. The approach below adopts the DocBook standard for tagging the table within the XML file with the correct elements and attributes. The XSL file transforms these DocBook elements into XHTML tables for Web page display.


Step 1. Stucturing the XML Document

The XML sample adheres to the DocBook standard for describing tables. However, this is only a small portion of the entire XML file for this table. It only covers the first two rows of the table. The complete table description is over 200 lines long.

				
****************************************************************
  The table element begins an XML table; the frame 
  attribute indicates if the table will have border lines 
****************************************************************
<table frame="all">
****************************************************************
  The tgroup element defines the number of columns in the 
  table, its alignment, spacing between columns and rows.
  The role attribute is used to define the width of the table. 
****************************************************************
<tgroup cols="6" align="left" colsep="1" rowsep="1" role="500">
****************************************************************
  The colspec element defines each column in the table
  and assigns it a name and width 
**************************************************************** 
 <colspec colname="c1" colwidth="20"/>
 <colspec colname="c2" colwidth="50"/>
 <colspec colname="c3" colwidth="30"/>
 <colspec colname="c4" colwidth="60"/>
 <colspec colname="c5" colwidth="60"/>
 <colspec colname="c6" colwidth="260"/>
****************************************************************
  The span element defines each rowspan in the table
  and assigns it a name and which columns it spans.  
**************************************************************** 
 <spanspec spanname="span1" namest="c1" nameend="c6"/>
 <spanspec spanname="span2" namest="c2" nameend="c3"/>
 <spanspec spanname="span2a" namest="c2" nameend="c3"/>
 <spanspec spanname="span2b" namest="c2" nameend="c3"/>
 <spanspec spanname="span2c" namest="c2" nameend="c3"/>
 <spanspec spanname="span2d" namest="c2" nameend="c3"/>
 <spanspec spanname="span2e" namest="c2" nameend="c3"/>
 <spanspec spanname="span2f" namest="c2" nameend="c3"/>
 <spanspec spanname="span2g" namest="c2" nameend="c3"/>
 <spanspec spanname="span2h" namest="c2" nameend="c3"/>
 <spanspec spanname="span3" namest="c4" nameend="c5"/>
 <spanspec spanname="span4" namest="c2" nameend="c6"/>
 <spanspec spanname="span5" namest="c3" nameend="c6"/>
 <spanspec spanname="span5a" namest="c3" nameend="c6"/>
 <spanspec spanname="span5b" namest="c3" nameend="c6"/>
 <spanspec spanname="span5c" namest="c3" nameend="c6"/>
****************************************************************
  The tbody element begins the actual construction of the
  table, followed by row and entry elements for each row and 
  column entry.  
****************************************************************
 <tbody>
  <row>
   <entry spanname="span1" align="center" role="#E7EBDE">
    <para>
     <emphasis role="bold">
      The Diagnostic Tool - Users, uses, suppliers and content dimensions
     </emphasis>
    </para>
   </entry>
  </row>
  <row>
   <entry colname="c1" morerows="9" rotate="1" valign="middle" role="#E7EBDE">
    <para>
     <mediaobject>
      <imageobject>
       <imagedata fileref="gateways/images/label1.gif" 
        format="gif" contentdepth="324" contentwidth="23" align="right"/>
      </imageobject>
      <textobject>
       <phrase>User, Uses, Supplier and Content Dimensions</phrase>
      </textobject>
     </mediaobject>
    </para>
   </entry>
   <entry spanname="span2" morerows="1" align="center" valign="middle" role="#E7EBDE">
    <para>
     <emphasis role="bolditalics">Dimension</emphasis>
    </para>
   </entry>
   <entry spanname="span3" align="center" valign="middle" role="#E7EBDE">
    <para>
     <emphasis role="bolditalics">Nature of Dimension</emphasis>
    </para>
   </entry>
   <entry colname="c6" morerows="1" align="center" valign="middle" role="#E7EBDE">
    <para>
     <emphasis role="bolditalics">Source and Nature of Constraint or Flexibility</emphasis>
    </para>
   </entry>
  </row>

			

Step 2. Creating the XSL Template Matches

The XSL file parses through the elements and attributes in the DocBook formatted XML files to create the XHTML file. It is somewhat complicated as it traverses the XML tree retrieving elements and attributes to serve as variables for defining the sizes of columns, rowspans, and colspans.


<xsl:template match="table">
 <xsl:variable name="tborder">
  <xsl:choose>
   <xsl:when test="@frame='all'">1</xsl:when>
   <xsl:otherwise>0</xsl:otherwise>
  </xsl:choose>
 </xsl:variable>
 <xsl:for-each select="tgroup">
  <xsl:variable name="cpadd"><xsl:value-of select="@colsep"/> </xsl:variable>
  <xsl:variable name="cspace"><xsl:value-of select="@rowsep"/></xsl:variable>
  <xsl:variable name="talign"><xsl:value-of select="@align"/></xsl:variable>
  <xsl:variable name="twidth"><xsl:value-of select="@role"/></xsl:variable>
  <table border="{$tborder}" width="{$twidth}" cellpadding="{$cpadd}" 
   cellspacing="{$cspace}" style="align:{$talign};" >
   <xsl:for-each select="tbody/row">
    <tr>
     <xsl:for-each select="entry">
      <xsl:variable name="ali"><xsl:value-of select="@align"/></xsl:variable>
      <xsl:variable name="vali"><xsl:value-of select="@valign"/></xsl:variable>
      <xsl:variable name="bgcolor"><xsl:value-of select="@role"/></xsl:variable>
      <xsl:choose>
       <xsl:when test="@spanname">
        <xsl:choose>
         <xsl:when test="@morerows">
          <xsl:variable name="mrows"><xsl:value-of select="@morerows + 1"/></xsl:variable>
          <xsl:variable name="span"><xsl:value-of select="@spanname"/></xsl:variable>
          <xsl:for-each select="ancestor::table/tgroup/spanspec[@spanname = $span]">
           <xsl:variable name="var">
            <xsl:value-of select="substring-after(@nameend,'c') + (-substring-after(@namest,'c'))+1"/>
           </xsl:variable>
           <xsl:choose>
            <xsl:when test="$bgcolor=''">
             <td rowspan="{$mrows}" colspan="{$var}" style="align:{$ali}; valign:{$vali};">
              <xsl:apply-templates 
              select="ancestor::table/tgroup/tbody/row/entry[@spanname=$span]/para/"/>
             </td>
            </xsl:when>
            <xsl:otherwise>
             <td rowspan="{$mrows}" colspan="{$var}" style="align:{$ali}; 
              valign:{$vali}; background-color:{$bgcolor};">
              <xsl:apply-templates 
              select="ancestor::table/tgroup/tbody/row/entry[@spanname=$span]/para/"/>
             </td>
            </xsl:otherwise>
           </xsl:choose>
          </xsl:for-each>
         </xsl:when>
         <xsl:otherwise>
          <xsl:variable name="span"><xsl:value-of select="@spanname"/></xsl:variable>
          <xsl:for-each select="ancestor::table/tgroup/spanspec[@spanname = $span]">
           <xsl:variable name="var">
            <xsl:value-of select="substring-after(@nameend,'c') + (-substring-after(@namest,'c'))+1"/>
           </xsl:variable>
            <xsl:choose>
             <xsl:when test="$bgcolor=''">
              <td colspan="{$var}" style="align:{$ali}; valign:{$vali};">
               <xsl:apply-templates 
               select="ancestor::table/tgroup/tbody/row/entry[@spanname=$span]/para/"/>
              </td>
             </xsl:when>
             <xsl:otherwise>
              <td colspan="{$var}" style="align:{$ali}; valign:{$vali}; background-color:{$bgcolor};">
               <xsl:apply-templates 
               select="ancestor::table/tgroup/tbody/row/entry[@spanname=$span]/para/"/>
              </td>
             </xsl:otherwise>
            </xsl:choose>
           </xsl:for-each>
          </xsl:otherwise>
         </xsl:choose>
        </xsl:when>
        <xsl:when test="@morerows">
         <xsl:variable name="mrows"><xsl:value-of select="@morerows + 1"/></xsl:variable>
         <xsl:variable name="col"><xsl:value-of select="@colname"/></xsl:variable>
         <xsl:variable name="cwidth">
          <xsl:value-of select="ancestor::table/tgroup/colspec[@colname=$col]/@colwidth"/>
         </xsl:variable>
          <xsl:choose>
           <xsl:when test="$bgcolor=''">
            <td rowspan="{$mrows}"  style="width:{$cwidth}; align:{$ali}; valign:{$vali};">
             <xsl:apply-templates select="para"/>&#160;</td>
           </xsl:when>
           <xsl:otherwise>
            <td rowspan="{$mrows}"  style="width:{$cwidth}; align:{$ali}; 
             valign:{$vali}; background-color:{$bgcolor};">
             <xsl:apply-templates select="para"/>&#160;</td>
           </xsl:otherwise>
         </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
         <xsl:variable name="col"><xsl:value-of select="@colname"/></xsl:variable>
         <xsl:variable name="cwidth">
          <xsl:value-of select="ancestor::table/tgroup/colspec[@colname=$col]/@colwidth"/>
         </xsl:variable>
         <xsl:choose>
          <xsl:when test="$bgcolor=''">
           <td style="width:{$cwidth}; align:{$ali}; valign:{$vali};"><
            <xsl:apply-templates select="para"/>&#160;</td>
             </xsl:when>
             <xsl:otherwise>
              <td style="width:{$cwidth}; align:{$ali}; valign:{$vali}; background-color:{$bgcolor};">
               <xsl:apply-templates select="para"/>&#160;</td>
             </xsl:otherwise>
            </xsl:choose>
           </xsl:otherwise>
          </xsl:choose>
         </xsl:for-each>
        </tr>
       </xsl:for-each>
      </table>
</xsl:template>
<!-- This template avoids creating a new table row within the table for each entry cell para -->
<xsl:template match="entry/para">
 <xsl:if test="@role='skip'">
  <br/><br/>
 </xsl:if>
 <xsl:if test="@role='noskip'">
   <br/>
 </xsl:if>
 <span class="ctcoltxt12">
  <xsl:apply-templates/>
 </span>
</xsl:template>  		

			

Sample Web Page with Table

A Web page with a table formatted and processed by the XML/XSL file above would appear like the sample shown below.

Sample Web Page with table