golang fo

2012年12月11日- 作者更新了本文和随附的样式表,以与FOP版本1.1一起使用。 他更改了<fo:page-sequence>元素和HTML <nobr>元素的实现(请参见<nobr>没有换行符的文本部分)。 样式表还使用标准的<fo:bookmark-tree><fo:bookmark><fo:bookmark-title>元素在PDF文件中生成书签 (请参见在<h1><h6>标题下生成书签 )。 请参阅“可下载资源”部分,以获取样式表的最新版本 。

2011年6月20日- 作者要求对<ul>无序列表部分的第二个代码列表进行两次更新。 他在两个fo:list-item-body元素的内容周围添加了一个fo:block元素,该元素将A Love Supreme更改为<fo:block>A Love Supreme</fo:block> ,并将The Joshua Tree更改为<fo:block>The Joshua Tree</fo:block>

我们都将HTML页面设计为在屏幕上看起来不错,但是打印这些Web页面通常是事后的事。 要创建网页的可打印版本,最好的方法是使用XSLT和XSL-FO生成PDF文件。 您可以使用开源XSLT处理器,XSL格式对象(XSL-FO)词汇表和格式对象引擎来完成此工作。 如果您已经知道如何使用XSL-FO和XSLT,那么本指南将提供宝贵的资源:它介绍了最常见HTML标记,并定义了如何将每个标记转换为格式化对象。 (如果你需要使用XSL-FO的背景下,尝试在这一主题的developerWorks教程,通过很容易找到相关主题 。)

本指南包含数十个示例,这些示例说明了如何编写XSLT样式表以完成从HTML元素到相应的格式对象(使用XSL-FO呈现的文档的基本构建块)的转换。

本指南中有关XSLT模板的快速说明; 几乎所有这些文件都包含以下文本:

<xsl:apply-templates select="*|text()"/>

该元素告诉XSLT处理器获取当前元素的所有文本和子元素,并对它们进行转换。 这种递归技术可确保处理所有HTML元素,无论它们如何相互嵌套。 有关XSLT和XSL-FO技术的详细信息,请参阅相关主题在本指南的结尾。

上下文示例

有关本参考资料的一些背景知识,您可以查看HTML文档( 下载 x-xslfo2app-samples.zip以查看everything.html),其中包含本指南中讨论的所有元素。 您还可以看到XSLT样式表xhtml-to-xslfo.xsl(位于x-xslfo2app-samples.zip中 ),其中包含本指南中提到的所有模板,以及本指南中介绍的大多数高级技术。配套教程。 要将样式表与HTML文件一起使用,请使用以下命令:

> fop -xml everything.html -xsl xhtml-to-xslfo.xsl -pdf everything.pdf

该命令告诉FOP呈现引擎使用xhtml-to-xslfo.xsl的规则将XHTML文件everything.html转换为格式化对象,然后从这些格式化对象生成一个名为everything.pdf的PDF文件。

这是PDF文件的屏幕截图:

如果愿意,您可以查看文件everything.pdf(位于x-xslfo2app-samples.zip中 )。 这将在letter尺寸的纸张上生成PDF文件。 要生成A4大小的PDF文件,请在上面命令的末尾添加-param page-size a4

缺少HTML元素

由于各种原因(其中大多数是合理的),本指南未涵盖某些HTML元素。 忽略它们的主要原因是它们在PDF文件中没有意义,这是格式设置对象转换的最常见结果。 W3C不推荐使用某些省略HTML元素,这也是将它们排除在外的很好理由。 在PDF上下文中,某些元素可能对您有意义。 告诉我你的想法; 如果您有很好的理由在本指南中添加其他HTML元素,我会考虑的(您可以使用本指南末尾的反馈表提出建议)。

转换HTML元素的指南

本指南向您展示如何将大多数HTML元素转换为XSL格式对象。 如果您正在在线查看此内容,则可以单击下面的任何链接直接进入对特定元素的讨论。 对于每个HTML元素,您将找到该元素的简要说明,相应的格式设置对象以及用于将HTML转换为XSL-FO的XSLT模板。 就像它们处理HTML元素一样,某些格式设置对象和模板非常简单,而有些则非常复杂。

与示例代码一样,我不得不做出一些针对特定情况的选择。 此处所有示例均假定最终您将使用格式化对象作为中介,以实现向PDF的转换。 我选择的一些值是任意的,但是我所做的大多数选择都是由为PDF文件定义的布局指导的,这是所有此转换的最终结果。 这种布局与我为developerWorks完成的两个教程中使用的布局相同。 当然,在使示例适合您自己的需求时,您将替换可以产生目标外观的值; 您无需遵循我们PDF文件的外观。

请记住,字母顺序虽然很适合参考,但对于直接阅读来说并不理想。 例如,尽管大多数用于构建表HTML标记的确在T之下,但它们被title元素按字母顺序中断。

  • <a name="...">命名锚点
  • <a href="#...">命名锚引用
  • <a href="...">锚点参考
  • <地址>地址
  • <b>粗体字
  • <big>较大的文字
  • <blockquote>块引用
  • <body>文件正文
  • <br>换行符
  • <标题>表的标题文本
  • <center>居中文字
  • <引用>引用
  • <code>一个代码示例
  • <dl>,<dt>和<dd>定义列表
  • <em>强调文字
  • <font color =“ ...”>更改文字颜色
  • <font face =“ ...”>更改文本字体
  • <font size =“ ...”>更改文字大小
  • <h1>至<h6>标题
  • <hr>水平尺
  • <i>斜体文字
  • <img>嵌入式图像
  • <kbd>键盘输入
  • <li>列表项
  • <nobr>没有换行符的文本
  • <ol>有序列表
  • <p>一段
  • <pre>预格式化的文本
  • <samp>示例文本
  • <small>较小字体的文本
  • <strike>删除线文本
  • <strong>强调文字
  • <sub>下标文字
  • <sup>上标文字
  • <table>表标签
  • <td>表格单元格
  • <tfoot>表格页脚
  • <th>表头中的单元格
  • <thead>表头
  • <title>文档标题
  • <tr>表格行
  • <tt>电传文本
  • <u>带下划线的文字
  • <ul>无序列表
  • <var>变量名

<a name="...">命名锚点

本指南着眼于转换三种不同类型的锚点元素:本条目中讨论的命名锚点 ,以及命名锚点引用和锚点引用 ,这两种内容将在字母指南的接下来的两个条目中讨论。 第三个条目包括一个XSLT模板示例 ,该示例演示了所有三种锚元素的转换。

命名的锚看起来像<a name="xyz" /> 。 通常将其转换为具有id<fo:block>元素。 这是典型的结果:

<fo:block id="xyz"/>

这似乎很简单,但是可能会出现问题,具体取决于文档的组织。 例如,在本教程的示例中,样式要求通过在标题文本之前插入水平线和分页符来呈现HTML <h1>元素。 该位置的分页符会导致命名锚点出现如下问题:

<a name="xslt"/>
<!-- A page break will be inserted here -->
<h1>Using XSLT style sheets</h1>

如果<h1>在新页面上开始,则创建指向命名锚点的链接会将用户带到上一页的末尾,这不是预期的。 要处理这种情况,请让处理器查看HTML文档中命名锚点之后的元素。 如果以下元素是<h1> ,则忽略命名锚; <h1>元素的XSLT模板在此实例中处理命名的锚点。 这是XSLT逻辑,即使在标题前有分页符的情况下,它也处理命名锚:

<xsl:template match="a"><xsl:choose><xsl:when test="@name"><xsl:if test="not(name(following-sibling::*[1]) = 'h1')"><fo:block line-height="0pt" space-after="0pt" font-size="0pt" id="{@name}"/></xsl:if></xsl:when>

指定following-sibling轴可确保样式表处理器检查位于命名锚点之后的元素。 如果此元素之后的第一个元素的名称不是 h1 ,则处理器将创建一个具有id<fo:block> 。 还要注意, <fo:block>元素将line-heightfont-sizespace-after属性设置为零; 您不想浪费任何垂直空间来渲染不可见的锚点。

<a href="#...">命名锚引用

要转换引用同一文档中另一个目标的锚标记,请将其转换为<fo:basic-link>元素。 对于同一文档的引用,请使用internal-destination属性。 例如,假设您有一个锚元素,如下所示:

For more information, see <a href="#chapter1">Chapter 1</a>.

您需要将anchor元素转换为此XSL-FO标记:

For more information, see
<fo:basic-link color="blue" internal-destination="chapter1">Chapter 1
</fo:basic-link>.

如果HTML锚点元素具有href属性,请检查其是否以井号( # )开头。 如果是这样,请将href属性用作<fo:basic-link>internal-destination 。 要使用该值,必须删除井号:使用XSLT substring()函数。 处理内部链接的最后一件事是在引用的部分中添加<fo:page-number-citation>

用于执行此转换的XSLT模板可能如下所示:

<xsl:template match="a"><xsl:choose><xsl:when test="@name">... The previous entry covered named anchors ...</xsl:when><xsl:when test="@href"><fo:basic-link color="blue"><xsl:choose><xsl:when test="starts-with(@href, '#')"><xsl:attribute name="internal-destination"><xsl:value-of select="substring(@href, 2)"/></xsl:attribute></xsl:when> <xsl:otherwise>... Handle external links here ...</xsl:otherwise></xsl:choose><xsl:apply-templates select="*|text()"/></fo:basic-link><xsl:if test="starts-with(@href, '#')"><xsl:text> on page </xsl:text><fo:page-number-citation ref-id="{substring(@href, 2)}"/></xsl:if></xsl:when></xsl:choose>
</xsl:template>

<fo:page-number-citation>元素意味着呈现的链接看起来像这样:

For more information, see Chapter 1 on page 73.

<a href="...">锚点参考

本指南中讨论的链接的最终类型是对URI的引用。 要在本教程的示例PDF文件中呈现这些内容,请使用<fo:basic-link>external-destination属性。 例如,假设您有一个锚元素,如下所示:

<a href="http://www.ibm.com/developerWorks/">IBM's developerWorks Web site
</a>

您可以将该元素转换为以下标记:

<fo:basic-link color="blue" external-destination="http://www.ibm.com/developerWorks/">IBM's developerWorks Web site
</fo:basic-link>

这是所有三种锚元素的完整XSLT模板:

<xsl:template match="a"><xsl:choose><xsl:when test="@name"><xsl:if test="not(name(following-sibling::*[1]) = 'h1')"><fo:block line-height="0" space-after="0pt" font-size="0pt" id="{@name}"/></xsl:if></xsl:when><xsl:when test="@href"><fo:basic-link color="blue"><xsl:choose><xsl:when test="starts-with(@href, '#')"><xsl:attribute name="internal-destination"><xsl:value-of select="substring(@href, 2)"/></xsl:attribute></xsl:when><xsl:otherwise><xsl:attribute name="external-destination"><xsl:value-of select="@href"/></xsl:attribute></xsl:otherwise></xsl:choose><xsl:apply-templates select="*|text()"/></fo:basic-link><xsl:if test="starts-with(@href, '#')"><xsl:text> on page </xsl:text><fo:page-number-citation ref-id="{substring(@href, 2)}"/></xsl:if></xsl:when></xsl:choose>
</xsl:template>

<address>地址

尽管未在<address>元素内标识典型地址的组成部分(电话号码,电子邮件地址,街道地址,城市等),但很少使用HTML元素定义了地址。 通常使用<address>元素,如下所示:

<address>Mrs. Mary Backstayge<br />283 First Avenue<br />Skunk Haven, MA  02718
</address>

请注意,该示例在<address>内使用<br>元素表示换行符。 这是等效的XSL-FO标记:

<fo:block>Mrs. Mary Backstayge<fo:block> </fo:block>
283 First Avenue<fo:block> </fo:block>
Skunk Haven, MA  02718</fo:block>

<address>的XSLT模板非常简单; 您只需将<address>元素转换为<fo:block>元素,然后处理文本和其中的任何其他元素。 这是模板:

<xsl:template match="address"><fo:block><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template>

<b>粗体字

转换粗体元素非常容易; 只需将其转换为具有font-weight="bold"属性的<fo:inline>元素。 这是一个例子:

<p>Jackdaws <b>love</b> my big sphinx of quartz.</p>

使用<fo:block><fo:inline>的基本XSL-FO元素来呈现此内容:

<fo:block>Jackdaws <fo:inline font-weight="bold">love</fo:inline>my big sphinx of quartz.
</fo:block>

请记住,从XSL-FO基础知识来看, <fo:block>元素总是导致换行,而<fo:inline>元素却不会。 因此,请使用<fo:inline>呈现<b>元素的内容。 这个简单的XSLT模板可以完成此工作:

<xsl:template match="b"><fo:inline font-weight="bold"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

注意, <xsl:apply-templates>元素的select属性选择了<b>元素的文本以及它可能包含的任何子元素。 例如,如果上面的标记是<p>Jackdaws <b><i>love</i></b> ... ,则选择<b>任何子元素可确保处理粗体和斜体元素。

<big>较大的文字

很少使用的<big> HTML元素使所包含的文本略大于周围的文本。 这是一个例子:

<p>Jackdaws <big>love</big> my big sphinx of quartz. </p>

这种转换很简单,因为XSL-FO教程示例中用作FO处理器的FOP工具现在支持百分比作为font-size属性的值。 (并非总是如此。)呈现<big>元素的一种合理方法是使用120%的font-size

<xsl:template match="big"><fo:inline font-size="120%"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

使用相对字体大小意味着彼此嵌套的多个<big>元素使从转换渲染的文本逐渐变大,就像嵌套的<big>元素在HTML中一样。 为示例段落生成的格式化对象将如下所示:

<fo:block>Jackdaws
<fo:inline font-size="120%">love</fo:inline> my big
sphinx of quartz. </fo:block>

当然,您可以根据需要修改示例模板以处理<big>元素。 您可以使字体更大,更改颜色等等。

<blockquote>块引用

为了处理块引用,该示例将其呈现为在左侧和右侧具有1.5厘米凹痕的单行距段落。 为此,请使用<fo:block>元素的start-indentend-indent属性。 这是<blockquote>元素:

<blockquote>When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.
</blockquote>

要将此摘录的格式设置为两边都缩进的段落,请使用以下XSL-FO标记:

<fo:block start-indent="1.5cm" end-indent="1.5cm">When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, ...
</fo:block>

使用此模板来转换<blockquote>元素:

<xsl:template match="blockquote"><fo:block start-indent="1.5cm" end-indent="1.5cm"><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template>

当然,您可以通过更改缩进属性值来修改报价的布局。

<body>文件正文

<body>元素的XSL-FO等效项是<fo:flow flow-name="xsl-region-body">元素。 为了保持HTML文档和XSLT样式表之间的对称性,此处的示例使用对<body>元素的处理来生成相应的XSL-FO元素。 对于示例文档, <fo:flow flow-name="xsl-region-body">元素包含以下六件事:

  • 文档标题( <head>内HTML title元素)
  • 令人振奋的消息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>

<br>换行符

您已经知道<fo:break>元素会导致换行; 要处理<br>元素,只需将一个<fo:break>元素嵌入另一个元素中。 例如,考虑以下标记:

<p>My mistress' eyes are nothing like the sun,<br/>Coral is far more red than her lips red.<br/>If snow be white, why then her breasts be dun,<br/>If hairs be wires, black wires grow on her head. ...
</p>

当您将此标记转换为XSL-FO元素时,结果如下所示:

<fo:block>My mistress' eyes are nothing like the sun, <fo:block> </fo:block>Coral is far more red than her lips red. <fo:block> </fo:block>If snow be white, why then her breasts be dun,<fo:block> </fo:block>If hairs be wires, black wires grow on her head.
</fo:block>

这是转换<br>元素的XSLT模板:

<xsl:template match="br"><fo:block> </fo:block>
</xsl:template>

<caption>表的标题文本

<caption>元素用于为表创建标题。 在XSL-FO中,这用<fo:table-caption>元素表示。 该指南在此处讨论<fo:table-caption><fo:table-and-caption>元素,即使FOP当前不支持它们。 理想情况下,此限制将很快得到纠正。

转换有一点点复杂:在HTML中, <caption>元素几乎可以出现在任何地方。 在XSL-FO中,它必须位于<fo:table-and-caption>元素内。 XSL-FO结构如下所示:

<table-and-caption><table-caption><table>
</table-and-caption>

这是用于转换<caption>元素的简单XSLT模板:

<xsl:template match="caption"><fo:table-caption><xsl:apply-templates select="*|text()"/></fo:table-caption>
</xsl:template>

HTML <caption>元素可能唯一的问题是它可能不会出现在您正在处理HTML <table> ,并且可能不会出现在<table>的第一个元素中。 这是<table>元素的模板,该模板试图处理这些问题:

<xsl:template match="table"><fo:table-and-caption><xsl:choice><xsl:when test=".//caption"><xsl:apply-templates select=".//caption[1]"></xsl:when><xsl:when test="preceding-sibling::caption"><xsl:apply-templates select="preceding-sibling::caption"/></xsl:when></xsl:choice><fo:table><xsl:apply-templates select="*[not(name()='caption')]"/></fo:table></fo:table-and-caption>
</xsl:template>

此模板首先检查<table>元素内是否存在任何<caption>元素。 如果有一个,它将选择第一个并进行处理。 (这使处理器可以忽略任何额外的<caption> 。)如果表内没有<caption> ,则处理器将查看表之前的第一个元素。 如果它是<caption> ,则可以假定它是表标题。 这里的最后一个麻烦是,当您处理实际的<table>本身时,必须对所有<caption>元素以外的所有内容使用<xsl:apply-templates>

<center>居中文字

要处理居中的文本,可以使用<fo:block>元素的text-align="center"属性。 鉴于此标记:

<center>Table of Contents
</center>

您可以将其转换为以下XSL-FO元素:

<fo:block text-align="center">Table of Contents
</fo:block>

这是一个XSLT模板,可以满足您的需求:

<xsl:template match="center"><fo:block text-align="center"><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template>

<cite>引用

<cite>元素通常以斜体显示。 为了使事情复杂一点,您可以编写XSLT模板,以便将<i>元素内包含的<cite>元素呈现为普通文本,以使其与周围的斜体文本区别开。 这是一些示例标记:

<p>When she was little, my daughter loved it when I read <cite>Goodnight Moon</cite> to her.<i>But <cite>Harold and the Purple Crayon</cite> was her favorite.</i>
</p>

要呈现此标记,请使用XSL-FO <fo:inline>元素:

<fo:block>When she was little, my daughter loved it when I read<fo:inline font-style="italic">Goodnight Moon</fo:inline> to her.<fo:inline font-style="italic">But<fo:inline font-style="normal">Harold and the Purple Crayon</fo:inline>was her favorite.</fo:inline>
</fo:block>

要处理斜体词组内的所有<cite>元素,请在转换前检查parent

<xsl:template match="cite"><xsl:choose><xsl:when test="parent::i"><fo:inline font-style="normal"><xsl:apply-templates select="*|text()"/></fo:inline></xsl:when><xsl:otherwise><fo:inline font-style="italic"><xsl:apply-templates select="*|text()"/></fo:inline></xsl:otherwise></xsl:choose>
</xsl:template>

如果<cite>元素的父元素是<i>元素,则将font-style更改为normal 。 否则,将其更改为italic 。 当<cite><i>元素相互嵌套时,此技术可以正确处理它们的组合。

<code>一个代码示例

渲染<code>元素需要使用等宽字体。 如您所料,您使用了<fo:inline>元素。 这是一些示例标记:

<p>If you're a Java programmer, an easy way to break a string apart
is with the <code>java.util.StringTokenizer</code> class.</p>

为了正确呈现此文本片段,您可以使用具有font-family="monospace"属性的<fo:inline>元素:

<fo:block>If you're a Java programmer, an easy way to break a string apart is with the <fo:inline font-family="monospace">java.util.StringTokenizer</fo:inline>class.
</fo:block>

这是一个XSLT模板,可以转换<code>元素:

<xsl:template match="code"><fo:inline font-family="monospace"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<dl><dt><dd>定义列表

尽管定义列表不如有序列表( <ol> )和无序列表( <ul> )常见,但它们在定义术语或选项列表时非常有用。 这是定义列表,为参数定义了一些选项:

<p>There are four valid values for the <code>text-align</code> parameter:</p>
<dl><dt>start</dt><dd>The text is aligned at the start of the paragraph, normally the left side.  </dd><dt>middle</dt><dd>The text is aligned at the middle of the paragraph.</dd><dt>end</dt><dd>The text is aligned at the end of the paragraph, normally the right side. </dd><dt>justify</dt><dd>The text is aligned at both the start and end of the paragraph.</dd>
</dl>

定义列表的典型格式是将术语( <dt>元素)以粗体显示在一行上,并在其下缩进定义,从下一行开始。 以下是<dl><dt><dd>的模板:

<xsl:template match="dl"><xsl:apply-templates select="*"/>
</xsl:template><xsl:template match="dt"><fo:block font-weight="bold" space-after="2pt"keep-with-next="always"><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template><xsl:template match="dd"><fo:block start-indent="1cm"><xsl:attribute name="space-after"><xsl:choose><xsl:when test="name(following::*[1]) = 'dd'"><xsl:text>3pt</xsl:text></xsl:when><xsl:otherwise><xsl:text>12pt</xsl:text></xsl:otherwise></xsl:choose></xsl:attribute><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template>

<dd>元素的模板中,处理器将查看下一个元素是否也是<dd>元素。 如果是,则当前<dt>元素必须对同一术语具有多个定义,因此处理器将在当前定义之后放置3点垂直空间。 否则,处理器将使用12个垂直空间点。 还要注意,即使FOP并不总是正确地处理模板,模板也使用<fo:block>元素的keep-with-next属性。

<em>强调文字

大多数浏览器以斜体显示强调的文本,因此您可以简单地将<em>元素转换为具有<font-style =“ italic”>属性的<fo:inline>元素。 从此标记开始:

<p>You <em>must<> disconnect the power supply before
you open the product housing.  </p>

您可以按以下方式在FO中进行渲染:

<fo:block>You <fo:inline font-style="italic">must</fo:inline> disconnectthe power supply before you open the product housing.
</fo:block>

XSLT模板的外观如下:

<xsl:template match="em"><fo:inline font-style="italic"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<font color="...">更改文字颜色

我将使用<font>元素的三个属性来演示如何转换XSL-FO元素: colorfacesize 。 对于color属性,可以使用十六进制RGB值(例如x33cc99 )或XSL-FO规范定义的16种颜色名称之一:

XSL-FO规范定义的16种颜色名称
aqua black blue fuchsia
gray green lime maroon
navy olive purple red
silver teal white yellow

XSLT模板假定FOP可以处理颜色值(如果有的话)。 默认颜色是black

<xsl:template match="font"><xsl:variable name="color"><xsl:choose><xsl:when test="@color"><xsl:value-of select="@color"/></xsl:when><xsl:otherwise><xsl:text>black</xsl:text></xsl:otherwise></xsl:choose></xsl:variable>...<fo:inline font-size="{$size}" font-family="{$face}"color="{$color}"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

请注意,XSLT模板创建一个变量来保存color属性的值。 该模板为colorfacesize创建变量,然后使用这些值构建<fo:inline>元素。

<font face="...">更改文本字体

<font>元素的face属性映射到XSL-FO font-family属性,但是有一个问题:FOP工具支持有限数量的字体。 font-family的有效值为:

  • serif
  • sans-serif
  • monospace
  • CourierCourier-BoldCourier-BoldObliqueCourier-Oblique
  • HelveticaHelvetica-BoldHelvetica-BoldObliqueHelvetica-Oblique
  • Symbol
  • Times-RomanTimes-BoldTimes-BoldItalicTimes-Italic

XSLT模板为字体创建变量,就像为颜色创建变量一样。 它将默认字体设置为sans-serif

<xsl:template match="font"><xsl:variable name="face"><xsl:choose><xsl:when test="@face"><xsl:value-of select="@face"/></xsl:when><xsl:otherwise><xsl:text>sans-serif</xsl:text></xsl:otherwise></xsl:choose></xsl:variable>...<fo:inline font-size="{$size}" font-family="{$face}"color="{$color}"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

此外,FOP工具提供了将Adobe Type 1字体和Truetype字体转换为XML字体规格文件的方法。 FOP使用这些文件以上述字体以外的其他字体呈现文本。 有关详细信息,请参见FOP文档。

<font size="...">更改文字大小

<font>元素的size属性映射到XSL-FO font-size属性。 这是用于处理HTML size属性的逻辑:

  • 如果size属性包含字符串pt (例如, size="24pt" ),请按原样使用值。
  • 如果size属性以加号或减号开头(例如size="+2"size="-1" ),则为字体使用相对大小; 例如,将+1映射到110%的相对字体大小。 (我随意选择了这些值,请随时进行更改。)
  • 如果size属性是1到7之间的数字,则将字体设置为任意大小。 (同样,如果愿意,请更改属性值。)
  • 作为最后的选择,将字体大小设置为12pt

这是<font>元素的整个XSLT模板。 最后,它使用先前初始化的变量来创建<fo:inline>元素:

<xsl:template match="font"><xsl:variable name="color"><xsl:choose><xsl:when test="@color"><xsl:value-of select="@color"/></xsl:when><xsl:otherwise><xsl:text>black</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><xsl:variable name="face"><xsl:choose><xsl:when test="@face"><xsl:value-of select="@face"/></xsl:when><xsl:otherwise><xsl:text>sans-serif</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><xsl:variable name="size"><xsl:choose><xsl:when test="@size"><xsl:choose><xsl:when test="contains(@size, 'pt')"><xsl:text>@size</xsl:text></xsl:when><xsl:when test="@size = '+1'"><xsl:text>110%</xsl:text></xsl:when><xsl:when test="@size = '+2'"><xsl:text>120%</xsl:text></xsl:when><xsl:when test="@size = '+3'"><xsl:text>130%</xsl:text></xsl:when><xsl:when test="@size = '+4'"><xsl:text>140%</xsl:text></xsl:when><xsl:when test="@size = '+5'"><xsl:text>150%</xsl:text></xsl:when><xsl:when test="@size = '+6'"><xsl:text>175%</xsl:text></xsl:when><xsl:when test="@size = '+7'"><xsl:text>200%</xsl:text></xsl:when><xsl:when test="@size = '-1'"><xsl:text>90%</xsl:text></xsl:when><xsl:when test="@size = '-2'"><xsl:text>80%</xsl:text></xsl:when><xsl:when test="@size = '-3'"><xsl:text>70%</xsl:text></xsl:when><xsl:when test="@size = '-4'"><xsl:text>60%</xsl:text></xsl:when><xsl:when test="@size = '-5'"><xsl:text>50%</xsl:text></xsl:when><xsl:when test="@size = '-6'"><xsl:text>40%</xsl:text></xsl:when><xsl:when test="@size = '-7'"><xsl:text>30%</xsl:text></xsl:when><xsl:when test="@size = '1'"><xsl:text>8pt</xsl:text></xsl:when><xsl:when test="@size = '2'"><xsl:text>10pt</xsl:text></xsl:when><xsl:when test="@size = '3'"><xsl:text>12pt</xsl:text></xsl:when><xsl:when test="@size = '4'"><xsl:text>14pt</xsl:text></xsl:when><xsl:when test="@size = '5'"><xsl:text>18pt</xsl:text></xsl:when><xsl:when test="@size = '6'"><xsl:text>24pt</xsl:text></xsl:when><xsl:when test="@size = '7'"><xsl:text>36pt</xsl:text></xsl:when><xsl:otherwise><xsl:text>12pt</xsl:text></xsl:otherwise></xsl:choose></xsl:when><xsl:otherwise> <xsl:text>12pt</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><fo:inline font-size="{$size}" font-family="{$face}"color="{$color}"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<h1><h6>标题

转换标题标签相对简单。 您将每个元素放入<fo:block>元素,并根据标题级别更改字体,字体大小和其他属性。 为了使顶层标题真正醒目,示例布局在<h1>文本之前放置了分页符和水平线。 以下是使用的格式选择:

HTML标签 字体大小 线高 之后的空间 其他
<h1> 28点 32点 22点 在文本之前添加分页符和水平线
<h2> 24点 28点 18点 没有
<h3> 21点 24点 14点 没有
<h4> 18点 21点 12点 没有
<h5> 16点 19点 12点 带下划线的文字
<h6> 14点 17点 12点 文本带有下划线和斜体

以下是一些标题元素:

<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 ReaderCannot 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 ReaderCannot Laugh Once Through the Whole Chapter, Unless Peradventure He Should Laugh at the Author
</fo:block>

<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' andpreceding-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>

生成书签

PDF文件可以包含指向文档不同部分的书签的分层树。 您可以使用XSL-FO <fo:bookmark-tree><fo:bookmark><fo:bookmark-title>元素从标题元素自动生成这些元素。 鉴于此HTML标记:

<h1>Sample text from Henry Fielding's Tom Jones</h1><h2>Book I. Containing as Much of the Birth...</h2><h3>Chapter VII. Containing Such Grave Matter...</h3>

样式表生成此XSL-FO标记:

<fo:bookmark-tree><fo:bookmark starting-state="hide" internal-destination="tomjones"><fo:bookmark-title>Sample text from Henry Fielding's Tom Jones</fo:bookmark-title><fo:bookmark starting-state="hide" internal-destination="N10017"><fo:bookmark-title>Book I.  Containing as Much of the Birth...</fo:bookmark-title><fo:bookmark starting-state="hide" internal-destination="N1001C"><fo:bookmark-title>Chapter VII.  Containing Such Grave Matter...</fo:bookmark-title></fo:bookmark></fo:bookmark></fo:bookmark></fo:bookmark-tree>

结果是这三个嵌套书签:

图1。

有关详细信息,请参见样式表中的generate-bookmarks模板。

<hr>水平尺

有一个特殊的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 ,它们会创建空白区域。

<i>斜体文字

HTML <i>元素很容易在XSL-FO中表示:只需将元素的文本放在带有font-style="italic">属性的<fo:inline> 。 这是一个非常类似于前面显示的<b>元素的示例:

<p>Jackdaws <i>love</i> my big sphinx of quartz.</p>

使用<fo:block><fo:inline>的基本XSL-FO元素来呈现此内容:

<fo:block>Jackdaws <fo:inline font-style="italic">love</fo:inline>my big sphinx of quartz.
</fo:block>

<fo:block>元素总是导致换行,而<fo:inline>元素则不会。 因此,请使用<fo:inline>呈现<i>元素的内容。 这个简单的XSLT模板可以完成此工作:

<xsl:template match="i"><fo:inline font-style="italic"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<img>嵌入式图像

<img>元素直接映射到XSL-FO <fo:external-graphic>元素。 将<img>转换为<fo:external-graphic>的麻烦之处在于FOP工具不支持HTML属性,例如width="200"widthheight属性必须包含一个度量单位(例如width="200px" )。 因此,将XSLT模板设置为让处理器在生成<fo:external-graphic>元素时查看HTML值。 这是模板:

<xsl:template match="img"><fo:block space-after="12pt"><fo:external-graphic src="{@src}"><xsl:if test="@width"><xsl:attribute name="width"><xsl:choose><xsl:when test="contains(@width, 'px')"><xsl:value-of select="@width"/></xsl:when><xsl:otherwise><xsl:value-of select="concat(@width, 'px')"/></xsl:otherwise></xsl:choose></xsl:attribute></xsl:if><xsl:if test="@height"><xsl:attribute name="height"><xsl:choose><xsl:when test="contains(@height, 'px')"><xsl:value-of select="@height"/></xsl:when><xsl:otherwise><xsl:value-of select="concat(@height, 'px')"/></xsl:otherwise></xsl:choose></xsl:attribute></xsl:if></fo:external-graphic></fo:block>
</xsl:template>

请注意,模板按原样使用src属性,并且处理器根据需要将度量单位添加到widthheight属性。

<kbd>键盘输入

用HTML <kbd>元素表示的键盘输入通常以稍大的等宽字体表示。 这是一个HTML示例:

<p>An easy way to delete a directory and all its contents (includingall subdirectories) is with the <kbd>rd /s</kbd> command.
</p>

您将使用以下XSL-FO元素来表示此示例:

<fo:block>An easy way to delete a directory and all its contents (includingall subdirectories) is with the <fo:inline font-family="monospace" font-size="110%">rd /s</fo:inline>command.
</fo:block>

XSLT模板执行此转换很简单:

<xsl:template match="kbd"><fo:inline font-family="monospace" font-size="110%"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<li>列表项

列表项的处理几乎就像一个段落,但有一些细微的差别。 由于这些差异取决于列表项的父项(这是<li> <ol>元素还是<ul>元素内的<li> <ul>元素?),因此请在<ol>元素和<ul>元素条目。

<nobr>没有换行符的文本

HTML <nobr>元素指定浏览器不应该换行,无论<nobr>元素中包含多少内容。 例如,采用以下HTML标记:

<p>On the Windows 2000 command line, you can use the ampersand (&amp;) to combine several commands into one statement. <nobr>pushd d:\projects\xslfo &amp; del *.fo &amp; rebuild.bat &amp; popd</nobr>is an example of this technique.
</p>

要以格式化对象的形式呈现此内容,请将<fo:inline>元素与wrap-option="no-wrap"属性一起使用。 不幸的是,FOP 1.1无法正确处理此问题,因此可以改用<fo:block>

<fo:block>On the Windows 2000 command line, you can use the ampersand (&amp;) to combine several commands into one statement.  <fo:block wrap-option="no-wrap">pushd d:\projects\xslfo &amp;del *.fo &amp; rebuild.bat &amp; popd </fo:block> is an example of this technique.
</fo:block>

进行此转换的XSLT模板非常简单:

<xsl:template match="nobr"><fo:block wrap-option="no-wrap"><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template>

好消息是,大多数<nobr>元素都是由自己设置的,因此这会在页面上生成所需的结果。 如果使用FOP以外的XSL-FO渲染引擎,请尝试将样式表更改为使用<fo-inline> 。 它可能会起作用。

<ol>有序列表

XSL-FO词汇表具有列表(包括有序列表)的专用元素。 这是一个示例HTML列表:

<p>A few of my favorite albums</p>
<ol><li>A Love Supreme</li><li>Remain in Light</li><li>London Calling</li><li>The Indestructible Beat of Soweto</li><li>The Joshua Tree</li>
</ol>

要在XSL-FO中表示列表项,必须使用几个元素: <fo:list-block><fo:list-item><fo:list-item-label><fo:list-item-body> 。 它们的用法如下:

  • <fo:list-block>元素包含整个列表。
  • 每个<fo:list-item>元素都包含一个列表项。 它包含<fo:list-item-label><list-item-body>元素。
  • <fo:list-item-label>是内容旁边的标签。 对于有序列表,例如, <fo:list-item-label>元素可能包含文本10. .。
  • <fo:list-item-body>包含列表项的实际内容。

以下是HTML标记作为格式对象显示的方式:

<fo:block>A few of my favorite albums</fo:block>
<fo:list-block provisional-distance-between-starts="0.75cm"provisional-label-separation="0.5cm" space-after="12pt"start-indent="1cm"><fo:list-item><fo:list-item-label end-indent="label-end()"><fo:block>1. </fo:block></fo:list-item-label><fo:list-item-body start-indent="body-start()"><fo:block>A Love Supreme</fo:block></fo:list-item-body></fo:list-item>...<!-- other list items appear here -->...
</fo:list-block>

进行转换的XSLT模板如下所示。 模板必须处理以下几件事:

  • 如果此列表出现在另一个列表中,请不要在其后插入任何空格。 否则,在列表后插入12点垂直空间。
  • 如果此列表不在其他任何列表中,则将其缩进1 cm 。 否则,将其缩进1 cm再加上每个其他列表的1.25 cm 。 例如,如果此列表深三层,则将列表缩进3.5 cm
  • 如果<ol>元素具有start属性,请使用该数字开始对列表项进行编号。 如果没有,只需使用XSLT position()函数对列表项进行编号。
  • 如果<ol>元素具有type属性,请使用其值来确定每个列表项的编号应如何格式化(罗马数字,阿拉伯数字或字母字符)。 它使用<xsl:number>元素的format属性执行此操作。

以下是XSLT模板,它们使用项目符号列表中的规则转换任何<ol><li>项:

<xsl:template match="ol"><fo:list-block provisional-distance-between-starts="1cm"provisional-label-separation="0.5cm"><xsl:attribute name="space-after"><xsl:choose><xsl:when test="ancestor::ul or ancestor::ol"><xsl:text>0pt</xsl:text></xsl:when><xsl:otherwise><xsl:text>12pt</xsl:text></xsl:otherwise></xsl:choose></xsl:attribute><xsl:attribute name="start-indent"><xsl:variable name="ancestors"><xsl:choose><xsl:when test="count(ancestor::ol) or count(ancestor::ul)"><xsl:value-of select="1 + (count(ancestor::ol) + count(ancestor::ul)) * 1.25"/></xsl:when><xsl:otherwise><xsl:text>1</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><xsl:value-of select="concat($ancestors, 'cm')"/></xsl:attribute><xsl:apply-templates select="*"/></fo:list-block>
</xsl:template><xsl:template match="ol/li"><fo:list-item><fo:list-item-label end-indent="label-end()"><fo:block><xsl:variable name="value-attr"><xsl:choose><xsl:when test="../@start"><xsl:number value="position() + ../@start - 1"/></xsl:when><xsl:otherwise><xsl:number value="position()"/></xsl:otherwise></xsl:choose></xsl:variable><xsl:choose><xsl:when test="../@type='i'"><xsl:number value="$value-attr" format="i. "/></xsl:when><xsl:when test="../@type='I'"><xsl:number value="$value-attr" format="I. "/></xsl:when><xsl:when test="../@type='a'"><xsl:number value="$value-attr" format="a. "/></xsl:when><xsl:when test="../@type='A'"><xsl:number value="$value-attr" format="A. "/></xsl:when><xsl:otherwise><xsl:number value="$value-attr" format="1. "/></xsl:otherwise></xsl:choose></fo:block></fo:list-item-label><fo:list-item-body start-indent="body-start()"><fo:block><xsl:apply-templates select="*|text()"/></fo:block></fo:list-item-body></fo:list-item>
</xsl:template>

这两个模板将<ol><li>元素转换为适当的XSL-FO元素。

<p>一段

HTML段落元素很容易转换为<fo:block>元素。 例如,采用以下段落:

<p>When in the Course of human events, it becomes necessary for one people to dissolve the political bonds which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.</p>

该段将转换为此XSL-FO标记:

<fo:block font-size="12pt" line-height="15ptspace-after="12pt">When in the Course of human events, it becomes necessary for one people to dissolve the political bonds which ...
</fo:block>

这是执行转换的简单XSLT模板:

<xsl:template match="p"><fo:block font-size="12pt" line-height="15pt"space-after="12pt"><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template>

该模板使用font-sizeline-heightspace-after属性的默认值实现。 显然,您可以根据需要更改这些值。

<pre>格式化的文本

<pre>元素有两个复杂之处。 您需要保留其中包含的所有空白,并且需要关闭XSL-FO引擎执行的自动自动换行。 按照约定,您还以等宽字体显示<pre>元素的内容。 此摘录是示例<pre>元素:

<pre>
public static void main(String args[])
{System.out.println("Hello, world!");
}
</pre>

要正确处理此<pre>元素示例,必须将其转换为以下XSL-FO标记:

<fo:block font-family="monospace" white-space-collapse="false"wrap-option="no-wrap">
public static void main(String args[])
{System.out.println("Hello, world!");
}
</fo:block>

XSLT模板很简单:

<xsl:template match="pre"><fo:block font-family="monospace"white-space-collapse="false"wrap-option="no-wrap"><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template>

<samp>示例文本

<samp>元素通常以稍大的等宽字体呈现。 尽管<samp>很少使用,但很容易转换为格式化对象。 这是一个示例<samp>元素:

<p>The <samp>DOCTYPE</samp> keyword lets yourefer to a DTD from your XML source document.</p>

将其转换为格式对象的XSLT模板简短而有趣:

<xsl:template match="samp"><fo:inline font-family="monospace"font-size="110%"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<small>较小字体的文本

<small>元素也很容易转换。 如您所料,它以略小的字体呈现。 因为<big>元素的模板以20%的font-size呈现了它,所以将<small>定义为<small> 20%是有意义的。 这是简单的XSLT模板:

<xsl:template match="small"><fo:inline font-size="80%"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

给定段落<p>The Lakers' chances for a fourth straight title are <small>slim</small>.</p> ,模板将生成以下标记:

<fo:block font-size="12pt" line-height="15pt" space-after="12pt">The Lakers' chances for a fourth straight title are<fo:inline font-size="80%">slim</fo:inline>.
</fo:block>

<big>元素一样,相互嵌套多个<small>元素会创建逐渐变小的文本。

<strike>删除线文本

HTML <strike>元素的实现很简单; 您可以使用属性text-decoration="line-through"创建一个<fo:inline>元素。 删除线文本对于突出显示文档的已删除部分很有用。 这是一个例子:

<p>The underline property<strike>is not currently supported by FOP.</strike>is now supported by FOP.</p>

呈现时,此段使文本清晰可见。 <strike>的XSLT模板很短:

<xsl:template match="strike"><fo:inline text-decoration="line-through"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

请注意,用于text-decoration属性的关键字既为否定关键字,也为肯定关键字。 如果出于某种原因,您想要一小段文字,而长line-through却关闭了line-through功能,则可以使用text-decoration="no-line-through"创建一个<fo:inline>元素text-decoration="no-line-through"属性。 您还可以指定多个值。 属性text-decoration="line-through underline"会同时删除线和下划线。

<strong>强调文字

<strong>元素通常以粗体显示。 这是完成窍门的简单模板:

<xsl:template match="strong"><fo:inline font-weight="bold"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<sub>标文字

要处理下标文本,请使用XSL-FO vertical-align属性更改文本的基线。 您通常还希望减小字体大小。 这是一个HTML示例:

<p>When I'm thirsty, nothing beats a cold glass of H<sub>2</sub>O.</p>

这是我们的XSLT模板:

<xsl:template match="sub"><fo:inline vertical-align="sub"font-size="75%"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<sup>上标文字

与下标文本一样,您可以使用XSL-FO vertical-align属性来处理上标文本。 这是一个HTML示例:

<p>Einstein's famous e=mc<sup>2</sup>is an equation that changed the world. </p>

这是我们的XSLT模板:

<xsl:template match="sup"><fo:inline vertical-align="super"font-size="75%"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<table>表标签

要处理HTML <table>元素,最大的挑战是确定XSL-FO表应具有的列数以及这些列的宽度。 FOP要求您为<fo:table-column>每一列提供一个<fo:table-column>元素。 处理完列后,只需为表内的所有元素调用XSLT模板。 这个XSLT模板处理如下的cols

<table cols="200 100pt" border="1">

您需要将cols属性转换为以下标记:

<fo:table-column column-width="200pt"/>
<fo:table-column column-width="100pt"/>

要实现该转换,您需要使用一种常见的XSLT技术,称为尾递归 。 您创建一个命名模板,该模板从属性值中获取第一个单词,将其转换为<fo:table-column>元素,然后调用自身以处理其余的属性值。 最终将处理整个属性。 以下是<table>元素的XSLT模板的外观:

<xsl:template match="table"><fo:table table-layout="fixed"><xsl:choose><xsl:when test="@cols"><xsl:call-template name="build-columns"><xsl:with-param name="cols" select="concat(@cols, ' ')"/></xsl:call-template></xsl:when><xsl:otherwise><fo:table-column column-width="200pt"/></xsl:otherwise></xsl:choose><fo:table-body><xsl:apply-templates select="*"/></fo:table-body></fo:table>
</xsl:template>

如果有cols属性,则处理器调用build-columns模板; 否则,它将创建单个<fo:table-column>元素。 还请注意, <fo:table>元素具有table-layout="fixed"属性; FOP当前发出不带此属性的警告消息。

让我们看一下build-columns模板:

<xsl:template name="build-columns"><xsl:param name="cols"/><xsl:if test="string-length(normalize-space($cols))"><xsl:variable name="next-col"><xsl:value-of select="substring-before($cols, ' ')"/></xsl:variable><xsl:variable name="remaining-cols"><xsl:value-of select="substring-after($cols, ' ')"/></xsl:variable><xsl:choose><xsl:when test="contains($next-col, 'pt')"><fo:table-column column-width="{$next-col}"/></xsl:when><xsl:when test="number($next-col) > 0"><fo:table-column column-width="{concat($next-col, 'pt')}"/></xsl:when><xsl:otherwise><fo:table-column column-width="50pt"/></xsl:otherwise></xsl:choose><xsl:call-template name="build-columns"><xsl:with-param name="cols" select="concat($remaining-cols, ' ')"/></xsl:call-template></xsl:if>
</xsl:template>

To start with, the template says to look at the length of the $cols parameter after removing any leading or trailing blanks (that's what the XSLT normalize-space() function does). Next, it breaks the $cols value into two parts: The substring before the first space, and everything after the first space. (Notice that when the processor calls this template from the template for the <table> element, it adds a space to the end of the value so there will always be at least one space.)

Now that the $cols parameter is split into two parts, the first part is processed:

  • If the value contains the string pt , assume it's a value like 200pt , and generate the <fo:table-column> element with it.
  • If the value is a number, add the string pt to the end of it and then generate the <fo:table-column> element. Use the XSLT number() function to convert the value to a number. If the value isn't a number (say it's number(xyz) , for example), the function returns the string NaN (not a number).
  • If neither of the previous rules applies, just create a new <fo:table-column> element with a column-width of 50pt .

After the processor handles the first part of the $cols parameter, the named template invokes itself with the last part of the $cols parameter, adding a space to the end of the value to make sure there is one.

<td> Table cell

The HTML <td> element maps well to the XSL-FO <fo:table-cell> element. As a default, the template calls for 3 points of space at the top, bottom, left, and right of the table cell. There are three HTML attributes you need to handle: colspan , rowspan , and align . You also handle the border attribute in a limited way.

The colspan and rowspan attributes map directly to the XSL-FO number-columns-spanned and number-rows-spanned attributes, so they aren't difficult to handle.

The HTML align attribute maps to the XSL-FO text-align attribute, but there are two different sets of values. The HTML align values of left , center , right , and justify map to the XSL-FO text-align values of start , center , end , and justify . The final complication here is that the alignment value might appear on the HTML <td> or <tr> or <thead> or <table> elements, so you have to check all of the ancestors until you find it. (Note that the text-align property is set on the <fo:block> element, not the <fo:table-cell> .)

Finally, if the <td> , <tr> , <thead> , or <table> element has a border="1" attribute, you draw a border around that cell of the table with the three XSL-FO properties border-style="solid" border-color="black" border-width="1pt" .

Here's the complete XSLT template, most of which is made up of <xsl:choose> elements that determine which XSL-FO properties to use:

<xsl:template match="td"><fo:table-cell padding-start="3pt" padding-end="3pt"padding-before="3pt" padding-after="3pt"><xsl:if test="@colspan"><xsl:attribute name="number-columns-spanned"><xsl:value-of select="@colspan"/></xsl:attribute></xsl:if><xsl:if test="@rowspan"><xsl:attribute name="number-rows-spanned"><xsl:value-of select="@rowspan"/></xsl:attribute></xsl:if><xsl:if test="@border='1' or ancestor::tr[@border='1'] orancestor::thead[@border='1'] orancestor::table[@border='1']"><xsl:attribute name="border-style"><xsl:text>solid</xsl:text></xsl:attribute><xsl:attribute name="border-color"><xsl:text>black</xsl:text></xsl:attribute><xsl:attribute name="border-width"><xsl:text>1pt</xsl:text></xsl:attribute></xsl:if><xsl:variable name="align"><xsl:choose><xsl:when test="@align"><xsl:choose><xsl:when test="@align='center'"><xsl:text>center</xsl:text></xsl:when><xsl:when test="@align='right'"><xsl:text>end</xsl:text></xsl:when><xsl:when test="@align='justify'"><xsl:text>justify</xsl:text></xsl:when><xsl:otherwise><xsl:text>start</xsl:text></xsl:otherwise></xsl:choose></xsl:when><xsl:when test="ancestor::tr[@align]"><xsl:choose><xsl:when test="ancestor::tr/@align='center'"><xsl:text>center</xsl:text></xsl:when><xsl:when test="ancestor::tr/@align='right'"><xsl:text>end</xsl:text></xsl:when><xsl:when test="ancestor::tr/@align='justify'"><xsl:text>justify</xsl:text></xsl:when><xsl:otherwise><xsl:text>start</xsl:text></xsl:otherwise></xsl:choose></xsl:when><xsl:when test="ancestor::thead"><xsl:text>center</xsl:text></xsl:when><xsl:when test="ancestor::table[@align]"><xsl:choose><xsl:when test="ancestor::table/@align='center'"><xsl:text>center</xsl:text></xsl:when><xsl:when test="ancestor::table/@align='right'"><xsl:text>end</xsl:text></xsl:when><xsl:when test="ancestor::table/@align='justify'"><xsl:text>justify</xsl:text></xsl:when><xsl:otherwise><xsl:text>start</xsl:text></xsl:otherwise></xsl:choose></xsl:when><xsl:otherwise><xsl:text>start</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><fo:block text-align="{$align}"><xsl:apply-templates select="*|text()"/></fo:block></fo:table-cell>
</xsl:template>

<tfoot> A table footer

The rarely used <tfoot> element creates a table footer. It contains a number of table row ( <tr> ) elements, each of which contains some number of table cells. To process it, you simply invoke the XSLT template for the <tr> elements that the <tfoot> element contains:

<xsl:template match="tfoot"><xsl:apply-templates select="tr"/>
</xsl:template>

<th> A cell in a table header

The HTML <th> element contains a cell of a table header. To process it, you create a <fo:table-cell> with 3-point padding all around (as specified earlier in the defaults for the <td> element). That <fo:table-cell> element contains an <fo:block> element with bold, centered text. The template checks this element's ancestors for the border="1" attribute; if any of them have that border attribute, it sets the XSL-FO border properties accordingly. Here's the complete XSLT template:

<xsl:template match="th"><fo:table-cellpadding-start="3pt" padding-end="3pt"padding-before="3pt" padding-after="3pt"><xsl:if test="@border='1' or ancestor::tr[@border='1'] orancestor::table[@border='1']"><xsl:attribute name="border-style"><xsl:text>solid</xsl:text></xsl:attribute><xsl:attribute name="border-color"><xsl:text>black</xsl:text></xsl:attribute><xsl:attribute name="border-width"><xsl:text>1pt</xsl:text></xsl:attribute></xsl:if><fo:block font-weight="bold" text-align="center"><xsl:apply-templates select="*|text()"/></fo:block></fo:table-cell>
</xsl:template>

<thead> A table header

You handle the rarely used <thead> element just like the <tfoot> element. Here's the simple XSLT template:

<xsl:template match="thead"><xsl:apply-templates select="tr"/>
</xsl:template>

<title> Document title

The assumption for all of these instructions is that you intend to ultimately convert the FO document to a PDF file, which has a layout you need to follow. To achieve the PDF layout called for in the tutorial example, you put the title of the document (the <title> element inside the <head> element inside the <html> element) in large, bold type, centered at the top of the page. Here's the XSLT template:

<xsl:template match="title"><fo:block space-after="18pt" line-height="27pt" font-size="24pt" font-weight="bold" text-align="center"><xsl:apply-templates select="*|text()"/></fo:block>
</xsl:template>

<tr> A table row

An HTML <tr> element maps directly to the XSL-FO <fo:table-row> element. Because most of the work of handling a table is in the template for the <td> element, all you have to do now is create the <fo:table-row> and invoke the XSLT templates for everything contained in the HTML <tr> element. Here's the simple template:

<xsl:template match="tr"><fo:table-row><xsl:apply-templates select="*|text()"/></fo:table-row>
</xsl:template>

<tt> Teletyped text

Teletyped text is rendered in a monospaced font. Here's the XSLT template:

<xsl:template match="tt"><fo:inline font-family="monospace"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

<u> Underlined text

To render underlined text, use the XSL-FO text-decoration property. Here's a short HTML sample:

<p>When typewriters ruled the earth, <u>underlining</u> was the most common way to highlight text.</p>

When you convert this to XSL-FO, use an <fo:inline> element with the text-decoration="underline" property:

<xsl:template match="u"><fo:inline text-decoration="underline"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

Note that the keywords for the text-decoration property are both negative and positive. If for some reason you wanted a short section of text that had the underline property turned off in a long section with underline turned on, you could create an <fo:inline> element with a text-decoration="no-underline" property. You can also specify multiple values; the property text-decoration="underline line-through" turns on both underlining and strikethrough.

<ul> An unordered list

Unordered lists are simpler than ordered lists and definition lists because the <fo:list-item-label> is a bullet for all of the items. Here's an HTML list to use for a sample:

<p>A few of my favorite albums</p>
<ul><li>A Love Supreme</li><li>Remain in Light</li><li>London Calling</li><li>The Indestructible Beat of Soweto</li><li>The Joshua Tree</li>
</ul>

You use the XSL-FO list elements <fo:list-block> , <fo:list-item> , <fo:list-item-label> , and <fo:list-item-body> . Here's how the HTML list looks when it's converted to XSL-FO:

<fo:block>A few of my favorite albums</fo:block>
<fo:list-block provisional-distance-between-starts="0.2cm"provisional-label-separation="0.5cm"space-after="12pt" start-indent="1cm"><fo:list-item><fo:list-item-label end-indent="label-end()"><fo:block>â??¢</fo:block></fo:list-item-label><fo:list-item-body start-indent="body-start()"><fo:block>A Love Supreme</fo:block></fo:list-item-body></fo:list-item>...<fo:list-item><fo:list-item-label end-indent="label-end()"><fo:block>â??¢</fo:block></fo:list-item-label><fo:list-item-body start-indent="body-start()"><fo:block>The Joshua Tree</fo:block></fo:list-item-body></fo:list-item>
</fo:list-block>

This template uses the Unicode entity â??¢ for the bullet character.

The XSLT templates that transform the <ul> and <li> items into the formatting objects follow these rules when processing the <ul> element:

  • If this list appears inside another list, don't insert any space after it.
  • If this list is not inside any other lists, indent it by 1 cm . Otherwise, indent it by 1 cm plus 1.25 cm for each additional list. For example, if this list is three levels deep, indent the list by 3.5 cm .

Here are the XSLT templates:

<xsl:template match="ul"><fo:list-block provisional-distance-between-starts="1cm"provisional-label-separation="0.5cm"><xsl:attribute name="space-after"><xsl:choose><xsl:when test="ancestor::ul or ancestor::ol"><xsl:text>0pt</xsl:text></xsl:when><xsl:otherwise><xsl:text>12pt</xsl:text></xsl:otherwise></xsl:choose></xsl:attribute><xsl:attribute name="start-indent"><xsl:variable name="ancestors"><xsl:choose><xsl:when test="count(ancestor::ol) or count(ancestor::ul)"><xsl:value-of select="1 + (count(ancestor::ol) + count(ancestor::ul)) * 1.25"/></xsl:when><xsl:otherwise><xsl:text>1</xsl:text></xsl:otherwise></xsl:choose></xsl:variable><xsl:value-of select="concat($ancestors, 'cm')"/></xsl:attribute><xsl:apply-templates select="*"/></fo:list-block>
</xsl:template><xsl:template match="ul/li"><fo:list-item><fo:list-item-label end-indent="label-end()"><fo:block>â??¢</fo:block></fo:list-item-label><fo:list-item-body start-indent="body-start()"><fo:block><xsl:apply-templates select="*|text()"/></fo:block></fo:list-item-body></fo:list-item>
</xsl:template>

<var> A variable name

A variable name is typically rendered in an italicized monospaced font. Use the XSL-FO font-family and font-style properties. 这是一个简短的示例:

<p>To run the FOP program, you must make sureyour <var>classpath</var> variableis set correctly.</p>

Here's the XSLT template that does the trick:

<xsl:template match="var"><fo:inline font-style="italic"font-family="monospace"><xsl:apply-templates select="*|text()"/></fo:inline>
</xsl:template>

翻译自: https://www.ibm.com/developerworks/xml/library/x-xslfo2app/index.html

golang fo

golang fo_HTML到格式化对象(FO)转换指南相关推荐

  1. Golang中的格式化输入输出

    Golang中的格式化输入输出 打印输出 在Go语言中有多种输出方式,不同的输出适用场景不同.归纳起来有三种,每种还分为3种方式(原内容.原内容+ln.原内容+f) PrintXX() FprintX ...

  2. JAXB实现xml与对象互相转换

    不需要引入任何外部jar包,JAXB自jdk1.5就已被集成,jdk1.7已升级为JAXB2. 1.xml报文 <?xml version="1.0" encoding=&q ...

  3. jquery对象PHP转换,jquery对象和DOM对象如何相互转换?

    本篇文章给大家介绍一下jquery对象和DOM对象的转换,有需要的朋友可以参考一下,希望对你有所帮助. 我们在上一篇文章jquery对象和DOM对象的区别有哪些?中也简单介绍了关于jquery对象和D ...

  4. 把json对象串转换成map对象

    2019独角兽企业重金招聘Python工程师标准>>> /**    * nc只支持简单的   * 把json对象串转换成map对象    * @param jsonObjStr e ...

  5. 如何将PHP对象数组转换成普通数组

    /** * 对象数组转为普通数组 * * AJAX提交到后台的JSON字串经decode解码后为一个对象数组, * 为此必须转为普通数组后才能进行后续处理, * 此函数支持多维数组处理. * * @p ...

  6. 用Format创建格式化对象举例

    1.把数字格式化为货币字符串: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.text.NumberFormat; ...

  7. Json对象与Json字符串的转化、JSON字符串与Java对象的转换

    一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...

  8. jQuery对象与dom对象的转换

    jQuery对象与dom对象的转换 只有jquery对象才能使用jquery定义的方法.注意dom对象和jquery对象是有区别的,调用方法时要注意操作的是dom对象还是 jquery对象. 普通的d ...

  9. json java typeof_Json对象与Json字符串的转化、JSON字符串与Java对象的转换

    一.Json对象与Json字符串的转化 1.jQuery插件支持的转换方式: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符 ...

最新文章

  1. MongoDB 计划缓存的影响
  2. c语言程序设计的反思,C语言程序设计教学反思.doc
  3. 关于iis中的网站,在ie下点击服务器控件无反应的问题
  4. C语言编写2048小游戏
  5. J2EE 中的安全第一部分 - J2EE安全介绍
  6. 软件工程电商系统数据库定义_某个电子商务系统项目的数据库设计
  7. php数组连起来,PHP 数组的拼接重组
  8. 原因为 1.无法找到文档; 2. 无法读取文档; 3. 文档的根元素不是xsd:schema
  9. 洛谷 P1508 Likecloud-吃、吃、吃
  10. bat批处理命令拨号上网
  11. 【数字信号处理】基于matlab GUI正选信号时域+频域分析【含Matlab源码 887期】
  12. Verilog设计参数化的译码器与编码器,以及设计4位格雷码计数器
  13. 为什么打工人 996 会猝死,而企业家 007 却不会?
  14. 香港流行乐黄金二十年——经典歌手(音乐人)全面回顾
  15. ​TCP和UDP的135、137、138、139、445端口的作用?​
  16. 每日一诗词 —— 行路难
  17. SAP EWM仓储管理系统与自动化仓储硬件对接方案介绍
  18. 在Element UI中表格根据数据动态变化显示表格的内容
  19. 腾讯兔小巢是什么?零代码如何连接企业微信机器人
  20. 微信小程序代码保存后,自动格式化代码

热门文章

  1. 500 Internal Privoxy Error
  2. 经典算法——数字三角形的三种解题方法:递推、记忆化搜索、动态规划
  3. 3D建模教程:3DMAX插件示例!
  4. Smarty-3.1.12配置
  5. 《轩辕剑之天之痕》开创周播新模式 明星阵容俘获众多年轻观众
  6. discuz应用中心打不开,显示空白解决方法
  7. 基金的回报率计算公式
  8. EPSON RX8010SJ RTC 简要功能说明及性能参数
  9. FINTECH自建科技生态介绍
  10. 苹果充电器不能充电了怎么办?