W3C home > Mailing lists > Public > www-xsl-fo@w3.org > October 2004

RE: conditional page-break table based on row number?

From: Roland Neilands <rneilands@pulsemining.com.au>
Date: Fri, 8 Oct 2004 08:44:30 +1000
To: "Tim Mooney" <mooney@dogbert.cc.ndsu.NoDak.edu>, <www-xsl-fo@w3.org>
Message-ID: <COEJLHCIGDNOEJIAMODEOEMEEKAA.rneilands@pulsemining.com.au>

Tim,

Two options:
1. Forget trying to insert the page break & let XSL-FO do it for you at the region-body margins. keep-together="always" works fine
on table rows in FOP.

2. XSL must be well formed XML. Set an XSL variable(*) for the page break attribute & use it in your table row instead.
eg:
  <xsl:variable name="breakvar">
    <xsl:choose>
      <xsl:when test="position() mod 2 = 1">
        <xsl:text>break-before="page"</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text></xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
...
<fo:table-row {$breakvar} keep-together="always">

(*) - Not in the same sense as other programming languages. Be careful of scope.
http://www.zvon.org/xxl/XSLTutorial/Books/Output/example34_ch9.html

Regards,
Roland

> -----Original Message-----
> From: www-xsl-fo-request@w3.org [mailto:www-xsl-fo-request@w3.org]On
> Behalf Of Tim Mooney
> Sent: Thursday, 7 October 2004 7:01 AM
> To: www-xsl-fo@w3.org
> Subject: conditional page-break table based on row number?
>
>
>
> [I haven't yet subscribed to this list, please Cc: me on any replies]
>
> I have some XML data like:
>
> <?xml version="1.0"?>
> <request>
> <common>
>   some common stuff, not important
> </common>
>
> <account>
>   <id>foo1</id>
>   <name>John. Q. Public</name>
> </account>
>
> <account>
>   <id>foo2</id>
>   <name>George Washington</name>
> </account>
>
> <!-- and so on, possibly hundreds of account elements -->
>
> </request>
>
> that I need to transform into PDF to look something like:
>
> -------------------------------------------------------------------------
> | Login ID:  foo1                    | Login ID: foo2                   |
> | Customer Name:  John Q. Public     | Customer Name: George Washington |
> -------------------------------------------------------------------------
> | Login ID:  foo3                    | Login ID: foo4                   |
> | Customer Name:  John Adams         | Customer Name: Thomas Jefferson  |
> -------------------------------------------------------------------------
> | Login ID:  foo5                    | Login ID: foo6                   |
> | Customer Name:  Abraham Lincoln    | Customer Name: Theodore Roosevelt|
> -------------------------------------------------------------------------
> | Login ID:  foo7                    | Login ID: foo8                   |
> | Customer Name:  Alexander Hamilton | Customer Name: Woodrow Wilson    |
> -------------------------------------------------------------------------
> | Login ID:  foo9                    | Login ID: foo10                  |
> | Customer Name:  Herbert Hoover     | Customer Name: John F. Kennedy   |
> -------------------------------------------------------------------------
>
>
> The rub is that I can't have any of the cells broken by a page break --
> the page break must happen between rows in the table, not within a cell.
>
> I'm using Apache fop 0.20.5, which doesn't have support for most of the FO
> that one would use to control that -- widows, orphans, keep-togethers, etc.
>
> If I just mark up static content with FO, I can just do a
>
>  	<fo:table-row break-before="page">
>
> before every N rows, let's say every 20 rows.  I have "perfect" output
> happening, with static content marked up and transformed to PDF via fop.
>
>
> The problem is that now I want to transform my XML data, and I'm having a
> miserable time trying to conditionally output the right fo:table-row.
>
> I want to do something like:
>
>   <xsl:for-each select="/request/account">
>    <xsl:sort select="./id" />
>
>    <!-- output a table row if position() mod 2 = 1 -->
>    <xsl:choose>
>     <xsl:when test="position() mod 2 = 1">
>      <!-- yes, should it be a normal fo:table-row or one with -->
>      <!-- a page break?                                       -->
>      <xsl:choose>
>        <xsl:when test="position() = 1">
>          <!-- this will be the first cell, don't force a page break here -->
>  	    <!-- just a normal page table row  -->
>          <fo:table-row keep-together.within-page="always">
>        </xsl:when>
>        <xsl:otherwise>
>          <!-- have we output enough so we should force a break?  -->
>          <xsl:choose>
>            <xsl:when test="position() mod 20 = 0">
>               <!-- filled a page, output table-row and page-break -->
>                  <fo:table-row break-before="page"
>                       keep-together.within-page="always">
>             </xsl:when>
>             <xsl:otherwise>
>               <!-- just a normal page table row  -->
>               <fo:table-row keep-together.within-page="always">
>             </xsl:otherwise>
>           </xsl:choose>
>         </xsl:otherwise>
>      </xsl:choose>
>     </xsl:when>
>    </xsl:choose>
>
>    <!-- now output a table cell -->
>
>    <xsl:apply-templates select="." mode="cutsheet" />
>
>    <!-- if postion() mode 2 = 0, we should output a row close, we've -->
>    <!-- finished a row of 2 cells, and should output a /fo:table-row -->
>    <xsl:if test="position() mod 2 = 0">
>     </fo:table-row>
>    </xsl:if>
> </xsl:for-each>
>
>
>
> The problem is that the xslt processor will choke on that, because it
> sees e.g.
>
>  	<xsl:if test="position() mod 2 = 0">
>  		</fo:table-row>
>  	</xsl:if>
>
> which is a mismatched tag.
>
>
>
>
> Next I tried:
>
>
> <xsl:for-each select="/request/account">
> <xsl:sort select="./iid" />
>
> <!-- output a table row if position() mod 2 = 1 -->
> <xsl:choose>
>   <xsl:when test="position() mod 2 = 1">
>     <!-- yes, should it be a normal fo:table-row or one with -->
>     <!-- a page break?                                       -->
>     <xsl:choose>
>       <xsl:when test="position() = 1">
>         <!-- just a normal page table row  -->
>         <fo:table-row keep-together.within-page="always">
>           <xsl:apply-templates select="." mode="cutsheet" />
>           <xsl:apply-templates select="following-sibling::."
>  				mode="cutsheet" />
>         </fo:table-row>
>       </xsl:when>
>       <xsl:otherwise>
>        <!-- have we output enough so we should force a break?  -->
>        <xsl:choose>
>         <xsl:when test="position() mod 28 = 0">
>           <!-- filled a page, output table-row and page-break -->
>              <fo:table-row break-before="page"
>                  keep-together.within-page="always">
>                  <xsl:apply-templates select="." mode="cutsheet" />
>                  <xsl:apply-templates select="following-sibling::."
>  					mode="cutsheet" />
>              </fo:table-row>
>         </xsl:when>
>         <xsl:otherwise>
>           <!-- just a normal page table row  -->
>           <fo:table-row keep-together.within-page="always">
>              <xsl:apply-templates select="." mode="cutsheet" />
>              <xsl:apply-templates select="following-sibling::."
>  					mode="cutsheet" />
>           </fo:table-row>
>         </xsl:otherwise>
>        </xsl:choose>
>       </xsl:otherwise>
>      </xsl:choose>
>   </xsl:when>
> </xsl:choose>
> </xsl:for-each>
>
>
>
> In other words, don't just output a fo:table-row, output both the opening
> and closing tags for the row, and try get two cells in between them.
>
> As I expected, that doesn't work correctly either, I end up with:
>
> -------------------------------------------------------------------------
> | Login ID:  foo1                    |                                  |
> | Customer Name:  John Q. Public     |                                  |
> -------------------------------------|                                  |
> | Login ID:  foo3                    |                                  |
> | Customer Name:  John Adams         |                                  |
> -------------------------------------|                                  |
> | Login ID:  foo5                    |                                  |
> | Customer Name:  Abraham Lincoln    |                                  |
> -------------------------------------------------------------------------
>
>
> and so on.
>
> Can anyone suggest a way to accomplish what I'm trying to do?  I'll gladly
> provide more info if I've left anything pertinent out.
>
> Tim
> --
> Tim Mooney                              mooney@dogbert.cc.ndsu.NoDak.edu
> Information Technology Services         (701) 231-1076 (Voice)
> Room 242-J6, IACC Building              (701) 231-8541 (Fax)
> North Dakota State University, Fargo, ND 58105-5164
>
>
>
Received on Thursday, 7 October 2004 22:46:36 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Wednesday, 3 October 2007 16:06:13 GMT