Question

How do I create table with dynamic number of columns with xsl fo. The number of columns varies with each input file but fixed for a single input file.

Here is a sample xml

<root>
<ColNo>3</ColNo>
<Objects>
<object id="1">
 <prop1 old="5" new="7">
 <prop2 old="2" new="1">
 <prop3 old="3" new="6">
</object>
</Objects>
</root>

I want a table with like below

Obj1
------------------------------------------
 prop1     | prop2          | prop3 
-------------------------------------------
old | new  |  old | new     | old  | new
-------------------------------------------
5   | 7    |  2   |  1      | 3    | 6

I came across to number-columns-repeated properties.. But unable to understand how to use it..

Also let me if there is any better approach.

Thanks.

Was it helpful?

Solution

You don't indicate how much you have tried, but I suspect not much since the input data are not well formed. And you also don't indicate how multiple rows of data are represented, so I've made a guess below by modifying the data adding additional information.

A complete solution follows. It uses the two available row-filling techniques and is similar to an illustration I use in the classroom (as well as an exercise) that engages them.

When I run the output below through a conforming XSL-FO processor, I get the table outlined as you have asked.

t:\ftemp>type table.xml 
<root>
<ColNo>3</ColNo>
<Objects>
<object id="1">
 <prop1 old="5" new="7"/>
 <prop2 old="2" new="1"/>
 <prop3 old="3" new="6"/>
 <prop1 old="15" new="17"/>
 <prop2 old="12" new="11"/>
 <prop3 old="13" new="16"/>
</object>
</Objects>
</root>

t:\ftemp>call xslt table.xml table.xsl table.fo 

t:\ftemp>type table.fo 
<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://www.w3.org/1999/XSL/Format" font-family="Times" font-size="20pt">
   <layout-master-set>
      <simple-page-master master-name="frame" page-height="210mm" page-width="297mm" margin-top="1cm" margin-bottom="1cm" margin-left="1cm" margin-right="1cm">
         <region-body region-name="frame-body"/>
      </simple-page-master>
   </layout-master-set>
   <page-sequence master-reference="frame">
      <flow flow-name="frame-body">
         <block>Obj1</block>
         <table border="solid 1pt" text-align="center">
            <table-header>
               <table-row>
                  <table-cell number-columns-spanned="2" border="solid 1pt">
                     <block>prop1</block>
                  </table-cell>
                  <table-cell number-columns-spanned="2" border="solid 1pt">
                     <block>prop2</block>
                  </table-cell>
                  <table-cell number-columns-spanned="2" border="solid 1pt">
                     <block>prop3</block>
                  </table-cell>
               </table-row>
               <table-row>
                  <table-cell border="solid 1pt">
                     <block>old</block>
                  </table-cell>
                  <table-cell border="solid 1pt">
                     <block>new</block>
                  </table-cell>
                  <table-cell border="solid 1pt">
                     <block>old</block>
                  </table-cell>
                  <table-cell border="solid 1pt">
                     <block>new</block>
                  </table-cell>
                  <table-cell border="solid 1pt">
                     <block>old</block>
                  </table-cell>
                  <table-cell border="solid 1pt">
                     <block>new</block>
                  </table-cell>
               </table-row>
            </table-header>
            <table-body>
               <table-cell border="solid 1pt">
                  <block>5</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>7</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>2</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>1</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>3</block>
               </table-cell>
               <table-cell border="solid 1pt" ends-row="true">
                  <block>6</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>15</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>17</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>12</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>11</block>
               </table-cell>
               <table-cell border="solid 1pt">
                  <block>13</block>
               </table-cell>
               <table-cell border="solid 1pt" ends-row="true">
                  <block>16</block>
               </table-cell>
            </table-body>
         </table>
      </flow>
   </page-sequence>
</root>
t:\ftemp>type table.xsl 
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/1999/XSL/Format" 
                version="1.0">

<xsl:output indent="yes"/>

<xsl:template match="/">
<root font-family="Times" font-size="20pt">

  <layout-master-set>
    <simple-page-master master-name="frame" 
                        page-height="210mm" page-width="297mm" 
                        margin-top="1cm" margin-bottom="1cm" 
                        margin-left="1cm" margin-right="1cm">
      <region-body region-name="frame-body"/>
    </simple-page-master>
  </layout-master-set>

  <page-sequence master-reference="frame">
    <flow flow-name="frame-body">
      <!--reposition to the top of table data-->
      <xsl:for-each select="root/Objects/object">
        <block>Obj<xsl:value-of select="@id"/></block>
        <table border="solid 1pt" text-align="center">
          <table-header>
            <!--header rows - use row-based row-grouping strategy-->
            <table-row>
              <xsl:for-each select="*[position() &lt;= /root/ColNo]">
                <table-cell number-columns-spanned="2" border="solid 1pt">
                  <block><xsl:value-of select="name(.)"/></block>
                </table-cell>
              </xsl:for-each>
            </table-row>
            <table-row>
              <xsl:for-each select="*[position() &lt;= /root/ColNo]">
                <table-cell border="solid 1pt"><block>old</block></table-cell>
                <table-cell border="solid 1pt"><block>new</block></table-cell>
              </xsl:for-each>
            </table-row>
          </table-header>
          <table-body>
            <!--body rows - use cell-based row-grouping strategy-->
            <xsl:apply-templates select="*"/>
          </table-body>
        </table>
      </xsl:for-each>
    </flow>
  </page-sequence>
</root>
</xsl:template>

<xsl:template match="object/*">
  <table-cell border="solid 1pt">
    <block><xsl:value-of select="@old"/></block>
  </table-cell>
  <table-cell border="solid 1pt">
    <xsl:if test="position() mod /root/ColNo = 0">
      <!--every time the last item of a row is encountered, signal end-->
      <xsl:attribute name="ends-row">true</xsl:attribute>
    </xsl:if>
    <block><xsl:value-of select="@new"/></block>
  </table-cell>
</xsl:template>

</xsl:stylesheet>


t:\ftemp>start table.fo 

t:\ftemp>rem Done! 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top