XSL-FO 高级技术8

概述 第 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 文件的抓屏:

everything.pdf 样本文件的抓屏

如果您愿意,可以查看文件 。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值