使用XSL-FO与Apache FOP生成报表时,如何在后续页面块为空时隐藏前置LOGO块
解决Apache FOP中根据页面内容是否存在隐藏LOGO块的问题
这个问题我之前也碰到过,核心就是要让LOGO的渲染逻辑和对应页面内容的存在性绑定起来,而不是像现在这样无条件硬编码每个LOGO块和分页。我给你两种解决思路,你可以根据实际情况选择:
思路一:针对固定页数的精准处理
如果你的报表页数是固定的(比如最多3页),可以直接给每个页面组加上条件判断,只有当对应页面内容存在且非空时,才渲染LOGO和页面内容:
<xsl:template match="LOGO"> <xsl:param name="imgLogo"> <xsl:value-of select="IMG" /> </xsl:param> <fo:external-graphic content-height="scale-to-fit" height="50pt" src="{$imgLogo}" /> </xsl:template> <xsl:template match="MYREPORT"> <!-- 处理第一页:无前置分页 --> <xsl:if test="PAG_1 and normalize-space(PAG_1) != ''"> <fo:block> <xsl:apply-templates select="LOGO" /> </fo:block> <fo:block> <xsl:value-of select="PAG_1" /> </fo:block> </xsl:if> <!-- 处理第二页:前置分页 --> <xsl:if test="PAG_2 and normalize-space(PAG_2) != ''"> <fo:block page-break-before="always"> <xsl:apply-templates select="LOGO" /> </fo:block> <fo:block> <xsl:value-of select="PAG_2" /> </fo:block> </xsl:if> <!-- 处理第三页:前置分页 --> <xsl:if test="PAG_3 and normalize-space(PAG_3) != ''"> <fo:block page-break-before="always"> <xsl:apply-templates select="LOGO" /> </fo:block> <fo:block> <xsl:value-of select="PAG_3" /> </fo:block> </xsl:if> </xsl:template>
关键说明:
- 用
<xsl:if>判断两个条件:PAG_x元素是否存在,以及经过normalize-space()处理后内容是否非空(避免只有空格的无效内容) - 第一页不需要前置分页,后续页面才添加
page-break-before="always" - 只有满足条件时,才会渲染对应的LOGO和页面内容块,彻底避免空页面的LOGO
思路二:通用的动态处理(支持任意页数)
如果未来报表页数可能变化,或者页面元素是动态生成的(比如PAG_1、PAG_2...PAG_N),可以用更灵活的遍历方式:
<xsl:template match="LOGO"> <xsl:param name="imgLogo"> <xsl:value-of select="IMG" /> </xsl:param> <fo:external-graphic content-height="scale-to-fit" height="50pt" src="{$imgLogo}" /> </xsl:template> <xsl:template match="MYREPORT"> <!-- 筛选出所有有效页面:以PAG_开头且内容非空的元素 --> <xsl:variable name="validPages" select="*[starts-with(local-name(), 'PAG_') and normalize-space(.) != '']" /> <!-- 按页面编号排序(确保PAG_1、PAG_2、PAG_3的顺序) --> <xsl:for-each select="$validPages"> <xsl:sort select="substring-after(local-name(), 'PAG_')" data-type="number" order="ascending" /> <!-- 除了第一个页面,添加前置分页 --> <xsl:if test="position() > 1"> <fo:block page-break-before="always" /> </xsl:if> <!-- 渲染LOGO --> <fo:block> <xsl:apply-templates select="../LOGO" /> </fo:block> <!-- 渲染页面内容 --> <fo:block> <xsl:value-of select="." /> </fo:block> </xsl:for-each> </xsl:template>
关键说明:
- 先通过
starts-with(local-name(), 'PAG_')筛选所有页面元素,再用normalize-space(.) != ''过滤空内容 - 用
<xsl:sort>按页面编号的数字顺序排序,避免因XML元素顺序混乱导致页面顺序错误 - 遍历过程中,只有第一个页面不加分页,后续页面自动添加分页逻辑
- 不管有多少个有效页面,都会自动匹配渲染,完全忽略空的或不存在的页面
这样修改后,当你输入只有PAG_1和PAG_2的XML时,就只会渲染对应的两组LOGO+内容,不会出现第三页的空LOGO了。
内容的提问来源于stack exchange,提问作者Alessandro
相关产品推荐
相关产品推荐

