xsl-fo 不分页
XSL格式设置对象(XSL-FO)标准是XSL标准中鲜为人知的部分之一(最突出的部分是XSLT)。 这是不幸的,因为XSL-FO对于诸如从XML文档生成PDF或Postscript文件之类的任务非常有用。 一般来说,XSL-FO控制XML文档的布局和表示。 实际上,大多数用户发现HTML页面适合在屏幕上阅读,但他们更喜欢PDF(因此也称为XSL-FO)作为打印副本。
控制分页符
XSL-FO的优点之一是,它可以根据需要自动将文档的文本放置在尽可能多的页面上。 页面装满后,XSL-FO会自动插入下一页。 不幸的是,该算法有时可能在错误的位置插入分页符,例如节标题和节内容之间的中断。 同样,它有时会将图形标签与实际图像分开,或将表标题与表行分开。
图1和图2说明了该问题。 在图1中,节标题位于页面底部,而节的其余部分位于下一页。
图1.部分标题后的分页符不合适
在图2中,图像标签已与图像分离。
图2.图像标签后的不适当的分页符
之所以会出现问题,是因为XSL-FO渲染器具有许多可使用的块,并且它不知道它们之间的关系。 它不知道标题是。 。 。 好吧,一个标题。 解决方案是告诉XSL-FO渲染器哪些块相互关联,或更具体地说,哪些块应保持在一起。 为此,该标准在keep and break类别中定义了几个属性。 keep-with-previous
和keep-with-next
属性指定是将一个块保留在上一个块还是下一个块。
该属性适用within-line
, within-column
和within-page
组件。 顾名思义,这些组件控制应将块分组的级别。 通常,我使用within-page
组件。
可接受的值为auto
(无特殊处理), always
(始终将块保留在同一页面上)或整数。 整数指定优先级,因此如果多个keep
属性发生冲突,则数字优先级最高的优先。 总体而言, always
值具有最高优先级。
清单1是一个样式表的摘录,该样式表使用keep
属性来防止标题和段落之间的中断或标签与图像之间的中断。 在XSL-FO中,该属性是一个属性。 (请参阅相关主题下载同伴代码的完整样式表)。
清单1. keep属性
<xsl:template match="doc:title" mode="keep">
<fo:block font-family="Times Roman"
font-size="12pt"
space-after="0.6em"
keep-with-next.within-page="always">
<xsl:apply-templates mode="keep"/>
</fo:block>
</xsl:template>
<xsl:template match="doc:figure" mode="keep">
<fo:block font-family="Times Roman"
font-size="8pt"
font-style="italic"
space-after="0.5em">
<xsl:value-of select="@label"/>
</fo:block>
<fo:block keep-with-previous.within-page="always">
<fo:external-graphic src="url({@src})"
width="{@width}"
height="{@height}"/>
</fo:block>
</xsl:template>
但是请注意,FOP(格式化对象处理器,Apache的开源XSL处理器)不能完全实现keep
属性。 如果使用清单1 ,则FOP会忽略keep
属性,这仍然可能导致不适当的分页符。 据我所知,唯一的商业渲染器,如XEP从RenderX或天线府XSL格式化(参见相关主题 )实现keep
性能-在写这篇文章的时间最少。
FOP解决方法
鉴于商业实现为标准提供了更完整的支持,因此购买副本可能是目前最好的解决方案。 不过,每台服务器的许可费用约为5,000美元(尽管有限的工作站许可价格可低至79美元),并非每个项目都能负担得起自己的XSL-FO渲染器。 在预算有限的项目早期阶段尤其如此。
尽管可以使用将FOP keep
属性用于解决方案,但这只是部分解决方案。 FOP仅识别表行的keep
属性。 有限的支持对于将表标题与表的其余部分组合在一起很有用,但是它也提供了一种变通方法,直到可以得到完全的支持为止。 该解决方案依赖于所谓的盲表 (专门为布局而引入的表,但实际上并不可见)。 如果您已完成任何HTML编码,则应该已经熟悉将表仅用于布局(例如,模拟列)。
清单2是另一个样式表摘录,它演示了使用FOP在盲表中的keep
属性。 此版本的样式表可防止出现不适当的分页符。 doc:figure
的模板创建一个盲表,在第一行带有标签,在第二行带有图像。 keep-with-previous
属性应用于第二行。
清单2.盲表
<xsl:template match="doc:figure" mode="blind">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row padding-bottom="0.5em">
<fo:table-cell>
<fo:block font-family="Times Roman"
font-style="italic"
font-size="8pt">
<xsl:value-of select="@label"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row keep-with-previous="always">
<fo:table-cell>
<fo:block>
<fo:external-graphic src="url({@src})"
width="{@width}"
height="{@height}"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="doc:section" mode="blind">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-number="1"/>
<fo:table-body>
<fo:table-row keep-with-next="always">
<fo:table-cell>
<xsl:apply-templates select="doc:title" mode="blind"/>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<xsl:apply-templates select="*[2]" mode="blind"/>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<xsl:apply-templates select="*[position() > 2]" mode="blind"/>
</xsl:template>
doc:section
模板类似。 再次,它将创建一个包含两行的盲表。 标题位于第一行,第一段位于第二行。 必须注意选择第一段。 我选择按位置选择段落以增加灵活性。
实际上,盲表最适合图形标签和表标题,而不是节标题。 FOP不愿意在单元格的中间中断,这意味着如果将较长的段落包含在盲表中,它将阻止中断。 反过来,这可能会导致分页符超出严格必要的范围。 您需要评估在文档中将该技术应用于何处。
一种改进可能是只为短段落生成一个盲表(您可以使用string-length()
函数评估段落string-length()
)。
摘要
借助XSL-FO,将XML文档转换为PDF并不困难,并且XSL-FO使您可以控制文档的最终布局,如本技巧演示所示。
翻译自: https://www.ibm.com/developerworks/xml/library/x-tippgbk/index.html
xsl-fo 不分页