DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> 將 XSL-FO 用於換頁和表
將 XSL-FO 用於換頁和表
編輯:XML詳解     

XSL 格式化對象(XSL-FO)標准是 XSL 標准中最鮮為人知的部分之一(人們更熟悉的部分是 XSLT)。這種情形令人遺憾,因為對於將 XML 文檔制作成 PDF 或 Postscript 文件這樣的任務,XSL-FO 會非常有用。一般說來,XSL-FO 控制 XML 文檔的布局和表現形式。實際上,大多數用戶發現 Html 頁面適合在電腦屏幕上閱讀,但他們更願意 PDF(因此使用 XSL-FO)作為印刷副本。

  控制換頁

  XSL-FO 的優點之一是可以自動將文檔的文本按需要放在多個頁面上。若一頁滿了,XSL-FO 自動插入下一頁。遺憾的是,這一算法有時可能會在錯誤的位置(如在段標題與段內容之間)插入換頁符。同樣,它有時將圖像標簽與實際圖像分開,或將表頭與表中的行分開。

  圖 1 和圖 2 說明了這種問題。在圖 1 中,段標題在頁的底部,而該段的余下部分卻在另一頁上。

圖 1. 段標題後面不恰當的換頁
將 XSL-FO 用於換頁和表

  在圖 2 中,圖像標簽與圖像分開。

圖 2. 圖像標簽後面不恰當的換頁
將 XSL-FO 用於換頁和表

  之所以出現這些問題,是因為 XSL-FO 渲染器要處理一長串塊,但卻不知道這些塊之間的關系。它不知道標題是……嗯,一個標題。解決方案是告訴 XSL-FO 渲染器哪些塊相互關聯,或(更明確地說)哪些塊應保留在一起。為此,標准在 keep 和 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(Formatting Objects Processor,格式化對象處理器)— Apache 的開放源碼 XSL 處理器 — 沒有完全實現 keep 特性。如果您使用 清單 1,FOP 就會忽略 keep 特性,而這樣仍可能會導致不恰當的換頁。就我所知,只有象 RenderX 的 XEP 或 Antenna House 的 XSL Formatter這樣的商業渲染器實現了 keep 特性 — 至少在我寫這篇文章時是如此。

  巧用 FOP

  既然商業實現對標准提供了更全面的支持,購買其副本可能是目前最佳的解決方案。但是,獲得許可證的費用大約是每台服務器 US$5,000(盡管受限的工作站許可證可能只要 US$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 不能分割表單元,這意味著如果將較長的段包括在隱形表中,那麼 FOP 將不會分割這一段。這進而會導致一些嚴格說來不必要的換頁。您需要考慮在文檔的何處使用這一技術。

  改進方法之一可能是只對短的段生成隱形表(可以用 string-length() 函數計算段的長度)。

  結束語

  感謝 XSL-FO,有了它,將 XML 文檔轉換成 PDF 就不再困難,XSL-FO 賦予您對文檔最終布局的許多控制權,本篇技巧已經演示了這一點。


 

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved