概述 | 第 1 页(共5 页) |
XSL-FO 常用于将 HTML 文档转换成 PDF。要做到这一点,使用 XSLT 将 HTML 元素转换成格式化对象,格式化对象是用 XSL-FO 显示的文档的基本构件。然后,再将格式化对象转换成 PDF。本章概述如何将 HTML 文档转换成相应的格式化对象。然后,下一章(使转换技术工作)将使用这些模板自动创建目录和一组书签,最后创建一个样本 PDF 文档。
本章只包含少数几个 HTML 元素来演示基本过程。对于所有我所见到在 PDF 转换中起作用的 HTML 元素,我已经整理了一本更完整的指南,说明它们的格式化对象中的等价对象和 XSLT 转换模板。一旦您学习了本教程中的技术,就可以参考该参考指南(请参阅参考资料)来对具有更多元素的 HTML 文档构建转换模板。
简要说明:本章示例中几乎所有的 XSLT 模板都包含这个元素:
<xsl:apply-templates select="*|text()"/>
该元素告诉 XSLT 处理器获取当前元素的所有文本及其子元素,并转换它们。不管 HTML 元素之间如何嵌套,这一递归技术确保处理所有这些元素。
<body> 文档主体 | 第 2 页(共5 页) |
<body>
元素的 XSL-FO 等价元素是 <fo:flow flow-name="xsl-region-body">
元素。为了保持 HTML 文档和 XSLT 样式表之间的对称,这里的示例将该处理用于 <body>
元素来生成相应的 XSL-FO 元素。对于示例文档,<fo:flow flow-name="xsl-region-body">
元素包含以下六项:
- 文档标题(
<head>
内的 HTMLtitle
元素) - 欢迎消息
developerWorks loves you!
- developerWorks URL
- 目录
- 文档中的所有内容
- 用于标识文档最后一页的
id
很明显,包括了其中的大部分项,使得文档有预期的布局。您可以更改 XSLT 模板来创建不同布局(例如,或许您喜欢标题页),或者可以使用多个样式表以多种格式显示相同信息。下面是完整的模板:
<xsl:template match="body">
<fo:flow flow-name="xsl-region-body">
<!-- Item 1 -->
<xsl:apply-templates select="/html/head/title"/>
<!-- Item 2 -->
<fo:block space-after="12pt" line-height="17pt"
font-size="14pt" text-align="center">
developerWorks loves you!
</fo:block>
<!-- Item 3 -->
<fo:block space-after="24pt" line-height="17pt"
font-size="14pt" text-align="center" font-weight="bold"
font-family="monospace">
ibm.com/developerWorks
</fo:block>
<!-- Item 4 -->
<xsl:call-template name="toc"/>
<!-- Item 5 -->
<xsl:apply-templates select="*|text()"/>
<!-- Item 6 -->
<fo:block id="TheVeryLastPage" font-size="0pt"
line-height="0pt" space-after="0pt"/>
</fo:flow>
</xsl:template>
<h1> 到 <h6> 标题 | 第 3 页(共5 页) |
转换标题标记相对比较简单;将每个标记放到 <fo:block>
元素中,并根据标题级别更改字体、字体大小和其它属性。要使顶层标题真正突出,示例布局在 <h1>
文本之前放置了分页符和一条水平线。下面是所用的格式化选项:
HTML 标记 | 字体大小 | 线高 | 后面的空格 | 其它 |
---|---|---|---|---|
<h1> | 28pt | 32pt | 22pt | 在文本的前面添加分页符和一条水平线 |
<h2> | 24pt | 28pt | 18pt | 无 |
<h3> | 21pt | 24pt | 14pt | 无 |
<h4> | 18pt | 21pt | 12pt | 无 |
<h5> | 16pt | 19pt | 12pt | 文本加下划线 |
<h6> | 14pt | 17pt | 12pt | 文本加下划线并用斜体字表示 |
下面是一些标题元素:
<h1>Sample text from Henry Fielding's <cite>Tom Jones</cite></h1>
<h2><b>Book I.</b> Containing as Much of the Birth of the Foundling
as Is Necessary or Proper to Acquaint the Reader with in the
Beginning of This History</h2>
<h3><b>Chapter VII.</b> Containing Such Grave Matter, That the Reader
Cannot Laugh Once Through the Whole Chapter, Unless Peradventure He
Should Laugh at the Author</h3>
这些元素被转换成下列格式化对象:
<fo:block break-before="page">
<fo:leader leader-pattern="rule"/>
</fo:block>
<fo:block font-family="serif" space-after="22pt" keep-with-next="always"
line-height="32pt" font-size="28pt" id="tomjones">
Sample text from Henry Fielding's
<fo:inline font-style="italic">Tom Jones</fo:inline>
</fo:block>
<fo:block font-family="serif" space-after="18pt" keep-with-next="always"
line-height="28pt" font-size="24pt" id="N10017">
<fo:inline font-weight="bold">Book I.</fo:inline>
Containing as Much of the Birth of the Foundling
as Is Necessary or Proper to Acquaint the Reader with in the
Beginning of This History
</fo:block>
<fo:block font-family="serif" space-after="14pt" keep-with-next="always"
line-height="24pt" font-size="21pt" id="N1001C">
<fo:inline font-weight="bold">Chapter VII.</fo:inline>
Containing Such Grave Matter, That the Reader
Cannot Laugh Once Through the Whole Chapter, Unless Peradventure He
Should Laugh at the Author
</fo:block>
<h1> 到 <h6> 标题 — 模板 | 第 4 页(共5 页) |
在 <h1>
元素的文本之前插入的分页符会使将已命名的锚与 <h1>
元素一起使用变得复杂。出于这个原因,<h1>
元素的 XSLT 模板检查前一个元素,以了解它是不是已命名的锚。下面是 <h1>
和 <h6>
元素的模板:
<xsl:template match="h1">
<fo:block break-before="page">
<fo:leader leader-pattern="rule"/>
</fo:block>
<fo:block font-size="28pt" line-height="32pt"
keep-with-next="always"
space-after="22pt" font-family="serif">
<xsl:attribute name="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>
<xsl:apply-templates select="*|text()"/>
</fo:block>
</xsl:template>
<xsl:template match="h6">
<fo:block font-size="14pt" line-height="17pt"
keep-with-next="always" space-after="12pt"
font-family="serif" font-style="italic"
text-decoration="underline">
<xsl:attribute name="id">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="generate-id()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates select="*|text()"/>
</fo:block>
</xsl:template>
最后注意一点:因为标题用于书签和目录,并且是有用的链接点,所以最好确保每个标题都有一个 id
。如果给定的标题元素已经有一个 id
属性,则使用它;否则,使用 XSLT 的 generate-id()
函数创建一个标识:
<xsl:attribute name="id">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="generate-id()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<hr> 水平的直线 | 第 5 页(共5 页) |
有一个特殊的 XSL-FO 元素 <fo:leader>
,它是为处理水平的直线而设计的。下面是一些 HTML 标记:
<p>Here's a short paragraph.</p>
<hr/>
<p>Here's another paragraph, following a horizontal rule.</p>
显示该内容的 XSL-FO 标记应该类似于:
<fo:block>
Here's a short paragraph.
</fo:block>
<fo:block>
<fo:leader leader-pattern="rule"/>
</fo:block>
<fo:block>
Here's another paragraph, following a horizontal rule.
</fo:block>
处理 <hr>
元素的 XSLT 模板非常简单:
<xsl:template match="hr">
<fo:block>
<fo:leader leader-pattern="rule"/>
</fo:block>
</xsl:template>
最后注意一点:leader-pattern
属性还支持 dots
(通常在目录中使用)的值和 space
(它创建空白区域)的值。