概述 | 第 1 页(共5 页) |
为结束本教程对如何使用格式化对象将 HTML 转换成 PDF 的介绍,本章中的三个模板集合了到目前为止您所学到的所有内容:
- 目录表模板
- 书签模板
- HTML 到 PDF 转换的示例
目录模板 | 第 2 页(共5 页) |
生成目录的模板(为了便于使用,命名为 toc
)相对比较简单。它仔细检查文档并获取所有 <h1>
、<h2>
、<h3>
和 <h4>
元素。对于每个元素,它创建一个块,这个块包含被引用的标题、<fo:leader>
点和该标题的起始页号。要确定每个标题正确的 id
,您一定会感到很复杂;处理该问题的方法与 HTML 标题元素的示例模板所做的一样(有关对该逻辑的讨论,请参阅 <h1> 到 <h6> 标题)。该模板还根据标题级别指定引用标题文本的缩排结果。下面是在处理 <body>
元素期间调用的 toc
模板:
<xsl:template name="toc">
<fo:block>
<fo:leader leader-pattern="rule" space-after="18pt"/>
</fo:block>
<fo:block space-after="12pt" id="TableOfContents"
line-height="21pt" font-size="18pt" text-align="start">
Table of Contents
</fo:block>
<fo:block line-height="11pt" font-size="8pt"
space-after="6pt">
If you're viewing this document online, you can
click any of the topics below to link directly to
that section.
</fo:block>
<xsl:for-each select="/html/body//h1 |
/html/body//h2 |
/html/body//h3 |
/html/body//h4">
<fo:block text-align-last="justify" line-height="17pt"
font-size="14pt" space-after="3pt" text-align="start"
text-indent="-1cm">
<xsl:attribute name="start-indent">
<xsl:choose>
<xsl:when test="name() = 'h1'">
<xsl:text>1cm</xsl:text>
</xsl:when>
<xsl:when test="name() = 'h2'">
<xsl:text>1.5cm</xsl:text>
</xsl:when>
<xsl:when test="name() = 'h3'">
<xsl:text>2cm</xsl:text>
</xsl:when>
<xsl:when test="name() = 'h4'">
<xsl:text>2.5cm</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:attribute>
<fo:basic-link color="blue">
<xsl:attribute name="internal-destination">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:when test="name(preceding-sibling::*[1]) = 'a' and
preceding-sibling::*[1][@name]">
<xsl:value-of select="preceding-sibling::*[1]/@name"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="generate-id()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates select="*|text()"/>
</fo:basic-link>
<fo:leader leader-pattern="dots"
leader-pattern-width="5pt"/>
<fo:page-number-citation>
<xsl:attribute name="ref-id">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:when test="name(preceding-sibling::*[1]) = 'a' and
preceding-sibling::*[1][@name]">
<xsl:value-of select="preceding-sibling::*[1]/@name"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="generate-id()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</fo:page-number-citation>
</fo:block>
</xsl:for-each>
</xsl:template>
书签模板的逻辑 | 第 3 页(共5 页) |
处理书签的 XSLT 模板名为 generate-bookmarks
。象 toc
模板一样,它处理 <h1>
、<h2>
、<h3>
和 <h4>
元素。这里的复杂点在于预期的结果要求书签是分层的;换句话说,顶级书签应该是 <h1>
元素,这些元素的下面是 <h2>
元素,<h2>
元素的下面是 <h3>
元素,以此类推。
要知道该模板的效率极差。它产生期望的结果,但它花了相当大的功夫来进行处理。因为 HTML 标题不是分层的,所以没有更好的方法来制作该模板;可以通过为每个标题生成一个单独的不分层的书签来简化该模板。
无论如何,在为您显示长模板本身之前,我将向您完整地介绍用于创建书签的重复的逻辑。该过程先从获取文档中的所有 <h1>
元素开始。对于每个元素,处理器:
- 为当前
<h1>
生成书签。 - 使用 XSLT 的
generate-id()
函数来创建该<h1>
的唯一id
。将该id
存储在名为$current-h1
的变量中。 - 获取所有出现在当前
<h1>
之后的<h2>
元素。对于每个元素。它:- 使用
generate-id()
函数来为该<h2>
之前的第一个<h1>
生成id
。 - 如果该
id
等于$current-h1
,那么处理器知道该<h2>
应该出现在当前<h1>
的书签之下。这意味着处理器:- 生成当前
<h2>
的书签。 - 使用
generate-id()
函数来创建该<h2>
的唯一id
。将该id
存储在名为$current-h2
的变量中。 - 获取所有出现在当前
<h2>
之后的<h3>
元素。对于每个元素,处理器:- 使用
generate-id()
函数来为该<h3>
之前的第一个<h2>
生成id
。 - 如果该
id
等于$current-h2
,那么它知道该<h3>
应该出现在当前<h2>
的书签之下。这意味着它:- 生成当前
<h3>
的书签。 - 使用
generate-id()
函数来创建该<h3>
的唯一id
。将该id
存储在名为$current-h3
的变量中。 - 获取所有出现在当前
<h3>
之后的<h4>
元素。对于每个元素,我们:- 使用
generate-id
函数来为该<h4>
之前的第一个<h3>
生成id
。 - 如果该
id
等于$current-h3
,那么它知道该<h4>
应该出现在当前<h3>
的书签之下。这意味着它生成当前<h4>
的书签。
- 使用
- 生成当前
- 使用
- 生成当前
- 使用
喔!如果您想通读它,可在书签模板中找到模板本身。
书签模板 | 第 4 页(共5 页) |
<xsl:template name="generate-bookmarks">
<fox:outline internal-destination="TableOfContents">
<fox:label>Table of Contents</fox:label>
</fox:outline>
<xsl:for-each select="/html/body//h1">
<xsl:variable name="current-h1" select="generate-id()"/>
<fox:outline>
<xsl:attribute name="internal-destination">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:when test="name(preceding-sibling::*[1]) = 'a' and
preceding-sibling::*[1][@name]">
<xsl:value-of select="preceding-sibling::*[1]/@name"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="generate-id()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<fox:label>
<xsl:value-of select="."/>
</fox:label>
<xsl:for-each select="following-sibling::h2">
<xsl:variable name="current-h2" select="generate-id()"/>
<xsl:if
test="generate-id(preceding-sibling::h1[1]) = $current-h1">
<fox:outline>
<xsl:attribute name="internal-destination">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$current-h2"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<fox:label>
<xsl:value-of select="."/>
</fox:label>
<xsl:for-each select="following-sibling::h3">
<xsl:variable name="current-h3" select="generate-id()"/>
<xsl:if
test="generate-id(preceding-sibling::h2[1]) = $current-h2">
<fox:outline>
<xsl:attribute name="internal-destination">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$current-h2"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<fox:label>
<xsl:value-of select="."/>
</fox:label>
<xsl:for-each select="following-sibling::h4">
<xsl:if
test="generate-id(preceding-sibling::h3[1]) = $current-h3">
<fox:outline>
<xsl:attribute name="internal-destination">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$current-h3"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<fox:label>
<xsl:value-of select="."/>
</fox:label>
</fox:outline>
</xsl:if>
</xsl:for-each>
</fox:outline>
</xsl:if>
</xsl:for-each>
</fox:outline>
</xsl:if>
</xsl:for-each>
</fox:outline>
</xsl:for-each>
</xsl:template>
HTML 转换到 PDF 的示例 | 第 5 页(共5 页) |
要结束对通过 XSL-FO 进行 HTML 转换的介绍,让我们研究一下这样一个 HTML 文档,它包含在附带的参考指南中讨论的所有元素。该示例还为您提供相应的 XSLT 样式表,该样式表包含了参考指南中 HTML 元素所有的模板以及在本教程这部分中讨论的大多数高级技术。请查看 并获取 HTML 源代码和 XSLT 样式表。要将该样式表用于 HTML 文件,使用下面的命令:
> java org.apache.xalan.xslt.Process -in everything.html
-xsl xhtml-to-xslfo.xsl -out everything.fo
顺便说一下,尽管该命令在这里被分成两行来适合本教程格式,但您应在一行中输入该命令。该命令告诉 Xalan 样式表引擎读取文件 everything.html,然后使用 xhtml-to-xslfo.xsl 中的规则来转换它。将转换的结果写入文件 everything.fo 中。如果您想要查看由该样式表创建的格式化对象,可以查看文件 。
一旦创建了 XSL-FO 文件,就可以使用该命令来创建 PDF:
> java org.apache.fop.apps.Fop everything.fo everything.pdf
下面是 PDF 文件的抓屏:
如果您愿意,可以查看文件 。