將 HTML 文檔轉換成 PDF 時需要幫助嗎?這篇參考指南將通過示例向您演示如何使用 XSLT 模板將 45 個常用 Html 元素轉換成格式化對象(Formatting Objects,FO)(出自 XSL-FO 詞匯表),從而能方便地使用 XSLT 轉換成 PDF。本文中的示例假定您正在使用基於 Java 的 XSLT 處理器 Xalan 和 Apache XML 項目的 FOP 工具,但本文介紹的大多數方法同樣適用於其它工具。
我們設計 HTML 頁面都是為了使它們在屏幕上看起來很好,但打印這些 Web 頁面卻往往是事後才想到的事。要創建 Web 頁面的可打印版本,最好的方法是使用 XSLT 和 XSL-FO 來生成 PDF 文件。您可以利用開放源碼 XSLT 處理器、XSL 格式化對象(XSL Formatting Objects,XSL-FO)詞匯表和格式化對象引擎來做這項工作。如果您已經知道如何使用 XSL-FO 和 XSLT,那麼本指南可為您提供有價值的參考資料:它逐一介紹最常用的 Html 標記並定義了如何將每個標記轉換成格式化對象。
本指南包含若干示例,這些示例說明了如何編寫將 Html 元素轉換成相應格式化對象的 XSLT 樣式表,格式化對象是用 XSL-FO 來處理文檔的基本構件。
關於本指南中 XSLT 模板的簡要說明;幾乎所有的模板都包含以下文本:
<xsl:apply-templates select="*|text()"/>
該元素告訴 XSLT 處理器獲取當前元素的所有文本和子元素並轉換它們。這一遞歸技術確保所有 Html 元素都能得以處理,不管它們是如何相互嵌套的。
示例的上下文
關於本參考資料的上下文,您可以打開 HTML 文檔 everything.html (下載 x-xslfo2app-samples.zip 查看 everything.html),它包含本指南中討論的所有元素。您還可以參閱 XSLT 樣式表 xhtml-to-xslfo.xsl,它包含本指南中引用的所有模板,以及本教程姊妹篇中介紹的大多數高級技術。要對 Html 文件使用該樣式表,請使用以下命令:
> Java org.apache.xalan.xslt.Process -in everything.Html
-xsl xHtml-to-xslfo.xsl -out everything.fo
順便說一下,必須在一行上輸入該命令,這裡是為了適應 developerWorks 格式才將它分成兩行。該命令告訴 Xalan 樣式表引擎(在教程示例中使用)去讀取文件 everything.html ,然後使用 xHtml-to-xslfo.xsl 樣式表中的規則來轉換它。轉換的結果寫入文件 everything.fo 。如果您想查看由該樣式表創建的格式化對象,可以查看文件 everything.fo。
有了 XSL-FO 文件之後,就可以使用以下命令來創建 PDF:
> Java org.apache.fop.aPPS.Fop everything.fo everything.pdf
以下是這個 PDF 文件的抓屏:
如果願意,可以查看文件 everything.pdf。
不見了的 Html 元素
出於種種原因(大多數是合理原因),本指南沒有介紹某些 HTML 元素。不介紹它們的主要原因是它們在 PDF 文件中沒有意義,這是格式化對象轉換最常見的結果。略去的 HTML 元素中有些已經被 W3C 棄用,這也是不介紹它們的一個正當理由。有些元素在 PDF 上下文中可能對於您是有意義的。請告訴我您的想法;如果您有很好的理由將其它 Html 元素加入到本指南,我將對其加以考慮(您可以使用本指南結尾處的反饋表單來提出建議)。
轉換 Html 元素指南
本指南向您演示如何將大多數 HTML 元素轉換成 XSL 格式化對象。如果您正在在線查看本文,可以單擊以下的任何鏈接,直接查看對某個特定元素的討論。對於每個 HTML 元素,您將看到對該元素的簡要描述、對應的格式化對象和將 HTML 轉換成 XSL-FO 的 XSLT 模板。同其要處理的 Html 元素一樣,有些格式化對象和模板很簡單,有些則非常棘手。
我必須針對手邊的案例做出一些特定選擇,這在采用示例代碼時不可避免。這裡的所有示例都假定您最終將使用格式化對象作為實現至 PDF 轉換的中間產物。我所選擇的幾個值是隨意的,但我所做的大多數選擇都參照為 PDF 文件(它是整個轉換操作的最終結果)定義的布局。這個布局和我已經為 developerWorks完成的兩篇教程中所用的相同。當然,為了使示例適應您自己的需要,可以替換成能生成您想要外觀的值;您不必遵照我們 PDF 文件的外觀。
請記住,字母順序盡管非常適合於引用,但不適合直接閱讀。例如,盡管用於構建表格的大多數 Html 標記都一起排在 T 下,但 title 元素卻攪亂了它們的字母順序。
<a name="..."> 命名錨點
<a href="#..."> 命名錨點引用
<a href="#..."> 錨點引用
<address> 地址
<b> 粗體字文本
<big> 較大的文本
<blockquote> 塊引用
<body> 文檔主體
<br> 換行符
<caption> 表的標題文本
<center> 居中文本
<cite> 引用
<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-height 、 font-size 和 space-after 屬性設為零;您不會希望把任何垂直方向上的空間浪費在顯示不可見的錨點上。
<a href="#..."> 命名錨點引用
要轉換引用同一文檔中另一目標的錨點標記,可將其轉換成 <fo:basic-link> 元素。對於對同一文檔的引用,可使用 internal-destination 屬性。例如,假定有如下所示的錨點元素:
For more information, see <a href="#chapter1">Chapter 1</a>.
需要將該錨點元素轉換成以下 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> 地址
我們很少用到這個 Html 元素,它可以定義地址,盡管在 <address> 元素中沒有標識出通常地址中的各組成部分(電話號碼、電子郵件地址、街道地址和城市等)。通常按如下方式使用 <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> 元素使得通過這種轉換所表示的文本逐漸變大,就象 Html 中嵌套的 <big> 元素所產生的效果一樣。例如,上面這段示例中,所生成的格式化對象類似於這樣:
<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-indent 和 end-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> 文檔主體
在 XSL-FO 中,與 <body> 元素相對應的是 <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:block> 元素會導致換行;要處理 <br> 元素,只需在一個 <fo:block> 元素中嵌入另一個 <fo:block> 元素即可。例如,考慮以下標記:
<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> 元素表示的。 盡管 FOP 目前還不支持 <fo:table-caption> 和 <fo:table-and-caption> 元素,本指南還是在這裡討論它們。順利的話,很快就會彌補這一缺陷。
對於這個轉換,有一個略微復雜的情況:在 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> ,則處理器會檢查表之前的首個元素。如果它是 <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>
以下是轉換 <code> 元素的 XSLT 模板:
<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> disconnect
the 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 元素進行轉換: color 、 face 和 size 。對於 color 屬性,可以使用十六進制 RGB 值(如 x33cc99 )或由 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 屬性的值。該模板創建 color 、 face 和 size 的變量,然後用這些值構建 <fo:inline> 元素。
<font face="..."> 更改文本字體
<font> 元素的 face 屬性映射至 XSL-FO font-family 屬性,但有一個問題:FOP 工具只支持數量有限的字體。 font-family 的有效值為:
serif
、 Courier-Bold 、 CourIEr-BoldOblique 或
sans-serif
monospace
CourIErCourIEr-Oblique
、 Helvetica-Bold 、 Helvetica-BoldOblique 或
HelveticaHelvetica-Oblique
、 Times-Bold 、 Times-BoldItalic 或 Times-Italic
Symbol
Times-Roman
如同處理顏色一樣,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 font-metric 文件。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>