65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 XSL 和 CSS 实现分页的 HTML 报告

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.96/5 (12投票s)

2008年3月16日

CPOL

2分钟阅读

viewsIcon

107594

downloadIcon

3024

构建具有动态页数 HTML 报表的一种可能方法。

报告预览,版本 A

Preview of Report A

报告预览,版本 B

Preview of Report B

引言

本文描述了一种构建具有动态页数的 HTML 报告的可能方法。我在开发 Web 应用程序上的 XSL 报告时,使用这种技术解决了分页问题。

背景

布局设计用于在 A4 纸张大小上打印。存储在 XML 文件中的数据作为输入传递给 XSL 转换。

代码

我们可以分析同一发票报告的两种情况,其中页数取决于订单数量。第一种情况是包含文档页眉(收件人地址)在所有页面的报告。在第二种情况下,文档页眉仅在第一页上。这两种情况之间的主要区别是详细部分(在本示例中为 OrderRows)的大小计算。

为了获得报告,我编写了如下代码

  1. ReportHeader - XSL 变量,包含图像徽标和文档的 Title
  2. DocumentRecipient - XSL 变量,包含有关客户的信息
  3. OrderHeader - XSL 变量,包含有关订单的信息
  4. OrderRowsHeader - XSL 变量,包含有关订购产品的标题表
  5. OrderRows - XSL for-each,用于订单行数据。报告版本 A 每页正好 40 行,报告版本 B 在第一页上 40 行,在所有后续页面上 46 行。
  6. Filler - XSL 模板,包含达到页面大小所需的空白行
  7. ReportFooter - XSL 变量,包含报告的页脚(公司地址)
  8. OrderTotals - XSL 变量,包含发票的总金额(仅在最后一页上打印)

CSS 分页命令

  <style type="text/css">
    .pagebreak {page-break-after: always;}
  </style>

关注点

分页的使用方法:如何计算行数以及确切地放置分页命令。

报告版本 A 的情况

    <xsl:for-each select="Order/OrderRows/OrderRow">
        <table class="tabledetails" cellspacing="0" style="table-layout:fixed">
            <tr>
                <td class="tdmargin" />
                <td style="width:70px" align="right" class="blueline">
                    <xsl:value-of select="ProductID" />
                    <xsl:value-of select="translate(' ', ' ', '&#160;')"/>
                </td>
                <td class="blueline" style="width:220px" >
                    <xsl:value-of select="ProductName" />
                    <xsl:value-of select="translate(' ', ' ', '&#160;')"/>
                </td>
                <td style="width:50px" align="right" class="blueline">
                    <xsl:value-of select="Quantity" />
                    <xsl:value-of select="translate(' ', ' ', '&#160;')"/>
                </td>
                <td style="width:50px" align="right" class="blueline">
                    <xsl:value-of select="concat('$ ', UnitPrice)" />
                    <xsl:value-of select="translate(' ', ' ', '&#160;')"/>
                </td>
                <td style="width:50px" align="right" class="blueline">
                    <xsl:value-of select="concat(Discount, ' %')" />
                    <xsl:value-of select="translate(' ', ' ', '&#160;')"/>
                </td>
                <td style="width:100px" align="right" class="blueline">
                    <xsl:value-of select="concat('$ ', ExtendedPrice)" />
                    <xsl:value-of select="translate(' ', ' ', '&#160;')"/>
                </td>
                <td class="tdmargin" />
            </tr>
        </table>
        <xsl:if test="(position() mod 40) = 0 ">
            <!--40 rows per page-->
            <xsl:call-template name="Filler">
                <xsl:with-param name="fillercount" select="1" />
            </xsl:call-template>

            <xsl:copy-of select="$ReportFooter" />

            <br class="pagebreak" />
            
            <xsl:copy-of select="$ReportHeader" />

            <xsl:call-template name="Filler">
                <xsl:with-param name="fillercount" select="1" />
            </xsl:call-template>

            <xsl:copy-of select="$OrderRecipient"/>

            <xsl:call-template name="Filler">
                <xsl:with-param name="fillercount" select="1" />
            </xsl:call-template>

            <xsl:copy-of select="$OrderHeader"/>

            <xsl:call-template name="Filler">
                <xsl:with-param name="fillercount" select="1" />
            </xsl:call-template>

            <xsl:copy-of select="$OrderRowsHeader"/>

        </xsl:if>
    </xsl:for-each>

报告版本 B 的情况

     <xsl:for-each select="Order/OrderRows/OrderRow">        
      <!-- ... --> 
    <xsl:choose>
            <!-- case of only one page-->
            <xsl:when test="(position() mod 40 = 0 and position() = 40)">
                <!--40 rows per page-->
                <xsl:call-template name="Filler">
                    <xsl:with-param name="fillercount" select="1" />
                </xsl:call-template>
    
                <xsl:copy-of select="$ReportFooter" />
    
                <br class="pagebreak" />
    
                <xsl:copy-of select="$ReportHeader" />
    
                <xsl:call-template name="Filler">
                    <xsl:with-param name="fillercount" select="2" />
                </xsl:call-template>
    
                <xsl:copy-of select="$OrderRowsHeader"/>
                
            </xsl:when>
            <!-- case of more than one page-->
            <xsl:otherwise>
                <xsl:if test="(40 - position() mod 46) = 0 and 
                              position() &gt; (40 + position() mod 40)">
                    <!--46 rows per page-->
                    <xsl:call-template name="Filler">
                        <xsl:with-param name="fillercount" select="1" />
                    </xsl:call-template>
    
                    <xsl:copy-of select="$ReportFooter" />
    
                    <br class="pagebreak" />
    
                    <xsl:copy-of select="$ReportHeader" />
    
                    <xsl:call-template name="Filler">
                        <xsl:with-param name="fillercount" select="2" />
                    </xsl:call-template>
    
                    <xsl:copy-of select="$OrderRowsHeader"/>
    
                </xsl:if>
    
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>

填充模板

    <!-- Template Filler-->
    <xsl:template name="Filler">
        <xsl:param name="fillercount" select="1"/>
        <xsl:if test="$fillercount > 0">
            <table class="tabledetails">
                <tr>
                    <td>
                        <xsl:value-of select="translate(' ', ' ', '&#160;')"/>
                    </td>
                </tr>
            </table>
            <xsl:call-template name="Filler">
                <xsl:with-param name="fillercount" select="$fillercount - 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

填充模板的简单用法:添加空白行

  <!-- Add two blank row -->
  <xsl:call-template name="Filler">
    <xsl:with-param name="fillercount" select="2" />
  </xsl:call-template>

填充模板的使用方法:如何计算最后一页上的空白行数

    <xsl:choose>
        <!-- case of only one page-->
        <xsl:when test="count(Order/OrderRows/OrderRow) &lt;= 40">
            <xsl:call-template name="Filler">
                <xsl:with-param name="fillercount" 
                   select="40 - (count(Order/OrderRows/OrderRow))"/>
            </xsl:call-template>
        </xsl:when>
        <!-- case of more than one page-->
        <xsl:otherwise>
            <xsl:call-template name="Filler">
                <!--(Rows per page = 40) -  (Rows in current page) - 
                    (Total Order rows = 3 ) - (Filler Row = 1)-->
                <xsl:with-param name="fillercount" select="40 - 
                   ( ( count(Order/OrderRows/OrderRow)-40 ) mod 40 ) - 3 - 1"/>
            </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
© . All rights reserved.