Search code examples
c#xmlvisual-studio-2008.net-3.5xsl-fo

XSL-FO Document: Inserting a break-before="page" attribute in a concrete fo:table-row


I have an XSL-FO document. This document has a lot of fo:table nested. There is an inner fo:table that has 9 columns and a lot of rows, in this example, first row for table header and other rows, from 1 to 20 for content. In the example below you can see that as a comment, for each FOPTable (fo:table) it is indicated a unique identifier, but this identifier is not always the same for the same table. It is generated randomly by the application that creates this XSL-FO document.

My question is: I want to find the table which has its first column header value set to HEADER_COL1 (this value is always the same), in this example, table identified with id:997 (rember that I cannot search for table according to this identifier since it changes randomly each time application creates the XSL-FO document). Once I have found the desired table I want below:

  1. How can I insert an attribute break-before="page" for a concrete fo:table-row item?
  2. I want to get the number of rows that this inner table has.

For example:

For example, If I want to insert this attribute for the 15th fo:table-row item, how can I do this? I want a parametrized generic method that take as an argument a number indicating the fo:table-row where to put this attribute.

I know that I can read the XSL-FO document using below:

string xmlFile = File.ReadAllText(@"C:\Temp\MyXSLFO.xml");
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(xmlFile);

But once loaded i have no idea on how to do this.

Note: I am using Visual Studio 2008, C# and .NET 3.5.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">

<fo:page-sequence force-page-count="no-force" master-reference="first" initial-page-number="1">
<fo:flow flow-name="xsl-region-body">
<!--  begin table FOPTable { id: 987 cur_size: 28.7 prv_size: 20.0 prev: <none> cols: 2 locks: 2 flow:FOPFlow: { type: BodyFlow size:4 region:FOPRegion: { type:3 extent:0.0}} } 
  --> 
<fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">
</fo:table>
<!--  endof table id FOPTable { id: 987 cur_size: 28.7 prv_size: 20.0 prev: <none> cols: 2 locks: 5 flow:FOPFlow: { type: BodyFlow size:4 region:FOPRegion: { type:3 extent:0.0}} } 
  --> 
<!--  begin table FOPTable { id: 992 cur_size: 28.7 prv_size: 20.0 prev: <none> cols: 2 locks: 2 flow:FOPFlow: { type: BodyFlow size:3 region:FOPRegion: { type:3 extent:0.0}} } 
  --> 
<fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">
</fo:table>
<!--  endof table id FOPTable { id: 992 cur_size: 28.7 prv_size: 20.0 prev: <none> cols: 2 locks: 4 flow:FOPFlow: { type: BodyFlow size:3 region:FOPRegion: { type:3 extent:0.0}} } 
  --> 
<!--  begin table FOPTable { id: 995 cur_size: 28.7 prv_size: 0.0 prev: <none> cols: 2 locks: 2 flow:FOPFlow: { type: BodyFlow size:2 region:FOPRegion: { type:3 extent:0.0}} } 
  --> 
<fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">

<!--  begin table FOPTable { id: 996 cur_size: 0.0 prv_size: 20.41 prev: 995 cols: 1 locks: 2 flow:null } 
  --> 
<fo:table font-size="8pt" font-family="sans-serif" table-layout="fixed">

<!--  begin table FOPTable { id: 997 cur_size: 0.0 prv_size: 20.409999999999997 prev: 996 cols: 9 locks: 5 flow:null } 
  --> 
<fo:table font-size="8pt" font-family="sans-serif" table-layout="fixed">
  <fo:table-column column-width="2.87cm" /> 
  <fo:table-column column-width="2.87cm" /> 
  <fo:table-column column-width="2.87cm" /> 
  <fo:table-column column-width="4.709999999999996cm" /> 
  <fo:table-column column-width="2.87cm" /> 
  <fo:table-column column-width="3.9cm" /> 
  <fo:table-column column-width="2.87cm" /> 
  <fo:table-column column-width="2.87cm" /> 
  <fo:table-column column-width="2.87cm" /> 
<fo:table-header>
<fo:table-row>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL1</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL2</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL3</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL4</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL5</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL6</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL7</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL8</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
  <fo:block>HEADER_COL9</fo:block> 
  </fo:table-cell>
  </fo:table-row>
  </fo:table-header>
<fo:table-body>
<fo:table-row>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW1_COL1_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW1_COL2_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW1_COL3_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW1_COL4_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW1_COL5_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW1_COL6_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-right="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block text-align="end">ROW1_COL7_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW1_COL8_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW1_COL9_VALUE</fo:block> 
  </fo:table-cell>
  </fo:table-row>


<!-- A LOT OF ROWS HERE -->

<!-- I want to insert a break-before attribute as below -->
<fo:table-row break-before="page">
<!-- columns here -->
</fo:table-row>

<!-- MORE ROWS HERE -->

<!-- LAST ROW NEXT -->
<fo:table-row>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW20_COL1_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW20_COL2_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW20_COL3_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW20_COL4_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW20_COL5_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW20_COL6_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-right="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block text-align="end">ROW20_COL7_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW20_COL8_VALUE</fo:block> 
  </fo:table-cell>
<fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" font-family="sans-serif" font-size="7pt">
  <fo:block>ROW20_COL9_VALUE</fo:block> 
  </fo:table-cell>
  </fo:table-row>
  </fo:table-body>
  </fo:table>
<!--  endof table id FOPTable { id: 997 cur_size: 28.7 prv_size: 20.409999999999997 prev: 996 cols: 9 locks: 6 flow:null } 
  --> 
</fo:table>

</fo:table>

</fo:flow>
</fo:page-sequence>
</fo:root>

Solution

  • Taking your data and removing all the cells and other non-important content, one could simply apply an identity XSL to the XSL FO and modify only the target row.

    starting with this XML:

    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    
        <fo:page-sequence force-page-count="no-force" master-reference="first" initial-page-number="1">
            <fo:flow flow-name="xsl-region-body">
                <fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">
                </fo:table>
                <fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">
                </fo:table>
                <fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">
                    <fo:table font-size="8pt" font-family="sans-serif" table-layout="fixed">
                        <fo:table font-size="8pt" font-family="sans-serif" table-layout="fixed">
                            <fo:table-column column-width="2.87cm" /> 
                            <fo:table-column column-width="2.87cm" /> 
                            <fo:table-column column-width="2.87cm" /> 
                            <fo:table-column column-width="4.709999999999996cm" /> 
                            <fo:table-column column-width="2.87cm" /> 
                            <fo:table-column column-width="3.9cm" /> 
                            <fo:table-column column-width="2.87cm" /> 
                            <fo:table-column column-width="2.87cm" /> 
                            <fo:table-column column-width="2.87cm" /> 
                            <fo:table-header>
                                <fo:table-row>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL1</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL2</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL3</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL4</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL5</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL6</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL7</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL8</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL9</fo:block> 
                                    </fo:table-cell>
                                </fo:table-row>
                            </fo:table-header>
                            <fo:table-body>
                                <fo:table-row/>
                                <fo:table-row/>
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                            </fo:table-body>
                        </fo:table>
                    </fo:table>
    
                </fo:table>
    
            </fo:flow>
        </fo:page-sequence>
    </fo:root>
    

    And applying this XSL which outputs everything as is, except for a template that inserts a page-break on the 12th row in the target table:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:fo="http://www.w3.org/1999/XSL/Format"
        version="2.0">
        <xsl:param name="breakrow" select="12"/>
    
        <xsl:template match="fo:table-row">
            <xsl:variable name="rowcnt" select="count(preceding-sibling::fo:table-row)"/>
            <xsl:choose>
                <xsl:when test="parent::fo:table-header">
                    <fo:table-row>
                        <xsl:apply-templates/>
                    </fo:table-row>
                </xsl:when>
                <xsl:when test="$rowcnt = $breakrow and ancestor::fo:table[1]/fo:table-header/fo:table-row[1]/fo:table-cell[1]/fo:block/text() = 'HEADER_COL1'">
                    <fo:table-row break-before="page"/>
                </xsl:when>
                <xsl:otherwise>
                    <fo:table-row/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    The result is this:

    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    
        <fo:page-sequence force-page-count="no-force" master-reference="first" initial-page-number="1">
            <fo:flow flow-name="xsl-region-body">
                <fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">
                </fo:table>
                <fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">
                </fo:table>
                <fo:table font-size="8pt" font-family="sans-serif" space-before.optimum="0.05cm" table-layout="fixed">
                    <fo:table font-size="8pt" font-family="sans-serif" table-layout="fixed">
                        <fo:table font-size="8pt" font-family="sans-serif" table-layout="fixed">
                            <fo:table-column column-width="2.87cm"/> 
                            <fo:table-column column-width="2.87cm"/> 
                            <fo:table-column column-width="2.87cm"/> 
                            <fo:table-column column-width="4.709999999999996cm"/> 
                            <fo:table-column column-width="2.87cm"/> 
                            <fo:table-column column-width="3.9cm"/> 
                            <fo:table-column column-width="2.87cm"/> 
                            <fo:table-column column-width="2.87cm"/> 
                            <fo:table-column column-width="2.87cm"/> 
                            <fo:table-header>
                                <fo:table-row>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL1</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL2</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL3</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL4</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL5</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL6</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL7</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL8</fo:block> 
                                    </fo:table-cell>
                                    <fo:table-cell padding-top="2.0pt" padding-left="2.0pt" border-style="solid" border-width="0.5pt" border-color="#000000" background-color="#D6DEE7" font-family="sans-serif">
                                        <fo:block>HEADER_COL9</fo:block> 
                                    </fo:table-cell>
                                </fo:table-row>
                            </fo:table-header>
                            <fo:table-body>
                                <fo:table-row/>
                                <fo:table-row/>
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row break-before="page"/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                                <fo:table-row/>                            
                            </fo:table-body>
                        </fo:table>
                    </fo:table>
    
                </fo:table>
    
            </fo:flow>
        </fo:page-sequence>
    </fo:root>
    

    I passed in 12 as a parameter and assumed that you had only one place ... the 12th row. You can certainly use "mod" and do every 12th row or whatever you desire.

    Like for instance:

     <xsl:when test="$rowcnt mod $breakrow = $breakrow - 1 and ancestor::fo:table[1]/fo:table-header/fo:table-row[1]/fo:table-cell[1]/fo:block/text() = 'HEADER_COL1'">
    

    And of course you can just add to the rows to get all the cell content output.