FOP table with cell having two blocks top and bottom aligned

2.3k views Asked by At

I would like to generate a table like the one in the image below using FOP:

desired table output

  • Left column can have 1 or any number of rows.
  • Block1 and Block2 in right column can have 1 or any number of lines. I want Block1 to be top aligned and Block2 to be bottom aligned.

For the right column I tried this:

<fo:table-cell number-rows-spanned="$rows-spanned" display-align="after">
    <fo:block>
        Block1 Lorem ipsum
    </fo:block>
    <fo:block>
        Block2 Lorem ipsum bla aaaa
    </fo:block>
</fo:table-cell>

but it aligns Block1 and Block2 to the bottom.

Any idea how to achieve the desired output?

2

There are 2 answers

0
lfurini On

(disclosure: I'm a FOP developer, though not very active nowadays)

After some pondering, I've thought of two possible solutions.

Solution 1 (recommended): using two spanning cells

Instead of spanning all the rows with a single cell containing both blocks, span just half the rows with a cell containing Block 1, and then use another row-spanning cell with display-align="after" for Block 2:

        <fo:table width="100%" table-layout="fixed">
            <fo:table-column column-width="50%"/>
            <fo:table-column column-width="50%"/>
            <fo:table-body>
                <fo:table-row>
                    <fo:table-cell border="1pt solid #000000">
                        <fo:block>header</fo:block>
                    </fo:table-cell>
                    <fo:table-cell border="1pt solid #000000" border-bottom="none" number-rows-spanned="6">
                        <fo:block color="red">Block 1 Lorem ipsum</fo:block>
                    </fo:table-cell>
                </fo:table-row>
                <!-- ... 5 more rows ... -->
                <fo:table-row>
                    <fo:table-cell border="1pt solid #000000">
                        <fo:block>item 6</fo:block>
                    </fo:table-cell>
                    <fo:table-cell border="1pt solid #000000" border-top="none" number-rows-spanned="5" display-align="after">
                        <fo:block color="blue">Block 2 Lorem ipsum bla aaaa</fo:block>
                    </fo:table-cell>
                </fo:table-row>
                <!-- ... the remaining 4 rows ... -->
            </fo:table-body>
        </fo:table>

Pros:

  • cleaner solution
  • no overlapping problems if there are few rows and the text blocks are several lines long

Cons:

  • the stylesheet to produce this would be more complicated (you have got to produce two row-spanning cells in the right row, taking into account that the number of rows could be odd / even)

Solution 2: using an extra column and margin tricks

You can define the table to have 3 columns, put Block 1 in a cell spanning all rows in column #2 and Block 2 spanning all rows in column #3, and creatively use margins to "move" Block 2 in the desired location:

        <fo:table width="12cm" table-layout="fixed">
            <fo:table-column column-width="4cm"/>
            <fo:table-column column-width="4cm"/>
            <fo:table-column column-width="4cm"/>
            <fo:table-body>
                <fo:table-row>
                    <fo:table-cell border="1pt solid #000000">
                        <fo:block>header</fo:block>
                    </fo:table-cell>
                    <fo:table-cell border="1pt solid #000000" number-rows-spanned="11">
                        <fo:block color="red">Block 1 Lorem ipsum</fo:block>
                    </fo:table-cell>
                    <fo:table-cell number-rows-spanned="11" display-align="after">
                        <!-- use margins to "push" the block in the previous column -->
                        <fo:block margin-left="-4cm" margin-right="4cm" color="blue">Block 2 Lorem ipsum bla aaaa</fo:block>
                    </fo:table-cell>
                </fo:table-row>
                <!-- ... the other 10 rows ... -->
            </fo:table-body>
        </fo:table>

Pro:

  • simpler template to produce this, as you have to care about column #2 and #3 in the first row only

Cons:

  • if there are few rows and long blocks of text, they could overlap
  • should the table have a page break inside it, both text would appear on the first page (as they are both in the first row)
  • this is probably a dirty trick, so I would not recommend doing this (I tested it with FOP 1.1 and 2.0 and it works, with an INFO message about the table being larger than the available space)
0
iMysak On

If you know height you can do this simply

<fo:table-cell text-align="left" height="5cm">
<fo:block>
    <fo:block-container height="25mm">
        <fo:block xsl:use-attribute-sets="myBorder">
            Block1 Lorem ipsum
        </fo:block>
    </fo:block-container>
    <fo:block-container height="25mm" xsl:use-attribute-sets="myBorder" display-align="after">
        <fo:block xsl:use-attribute-sets="myBorder" vertical-align="bottom" display-align="after">
             Lorem ipsum bla aaaa
        </fo:block>
    </fo:block-container>
</fo:block>