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 Wednesday, 6 October 2004 21:05:07 UTC