跳轉到內容

XQuery/XSL-FO 表格

來自華夏公益教科書

您希望能夠建立適合書籍出版的高質量表格輸出。

為了實現這一目標,我們將把 XML 轉換為 XSL-FO 表格。與 HTML 不同,XML-FO 允許您建立文字流,並且您可以設定有關物件跨越頁面邊界的方式的規則。

示例輸入

[編輯 | 編輯原始碼]

這是一個示例 XML 檔案,其中包含一個有兩列的表格。

<table heading="Department Phone Extensions">
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
   <Person>
      <Name>John Doe</Name>
      <Extension>1234</Extension>
   </Person>
   <Person>
      <Name>Sue Smith</Name>
      <Extension>5678</Extension>
   </Person>
</table>

我們希望這個 XML 檔案以兩列呈現,第一列包含姓名,第二列包含電話分機號。它應該看起來像這樣。

部門電話分機號
姓名 分機號
John Doe 1234
Sue Smith 5678

示例 FO 檔案

[編輯 | 編輯原始碼]

以下是您需要建立表格的 XML-FO 佈局的核心(不控制列寬)。

<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <fo:block font-size="14pt" padding="10px" font-family="Verdana">Department Phone Extensions</fo:block>
    <fo:block font-size="10pt">
        <fo:table border="solid" border-collapse="collapse">
            <fo:table-header>
                <fo:table-row space-after="10px">
                    <fo:table-cell>
                        <fo:block font-weight="bold">Name</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block font-weight="bold">Extension</fo:block>
                    </fo:table-cell>
                </fo:table-row>
            </fo:table-header>
            <fo:table-body>
                <fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
<fo:table-row>
                    <fo:table-cell>
                        <fo:block>John Doe</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>1234</fo:block>
                    </fo:table-cell>
                </fo:table-row>
                <fo:table-row>
                    <fo:table-cell>
                        <fo:block>Sue Smith</fo:block>
                    </fo:table-cell>
                    <fo:table-cell>
                        <fo:block>5678</fo:block>
                    </fo:table-cell>
                </fo:table-row>
            </fo:table-body>

        </fo:table>
    </fo:block>
</fo:block>

使用 XQuery 進行轉換

[編輯 | 編輯原始碼]

使用 XSLT 進行轉換

[編輯 | 編輯原始碼]

注意:此示例應移至有關 XSLT 的書籍中。應使用 XQuery 型別切換轉換來執行此操作。

我們可以使用 XSLT 指令碼將 XML 結構轉換為 XSL-FO。此通用指令碼僅要求 XML 表格的根名為 table 並且具有 heading 屬性。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format"
    exclude-result-prefixes="xs" version="2.0">
    <xsl:template match="/table">
        <fo:block>
            <fo:block font-size="14pt" padding="10px" font-family="Verdana">
                <xsl:value-of select="@heading"/>
            </fo:block>
            <fo:block font-size="10pt">
              <fo:table border="solid" border-collapse="collapse" >
                <fo:table-header>
                    <fo:table-row>
                        <xsl:for-each select="*[1]/*">
                            <fo:table-cell>
                                <fo:block font-weight="bold">
                                    <xsl:value-of select="name(.)"/>
                                </fo:block>
                            </fo:table-cell>
                        </xsl:for-each>
                    </fo:table-row>
                </fo:table-header>
                <fo:table-body>
                    <xsl:apply-templates select="*"/>
                </fo:table-body>
              </fo:table>
            </fo:block>
        </fo:block>
    </xsl:template>
    <xsl:template match="*">
        <fo:table-row>
            <xsl:for-each select="*">
                <fo:table-cell>
                    <fo:block>
                        <xsl:value-of select="."/>
                    </fo:block>
                </fo:table-cell>
            </xsl:for-each>
        </fo:table-row>
    </xsl:template>
</xsl:stylesheet>

XQuery 整合

[編輯 | 編輯原始碼]

最後,我們可以使用 XQuery 指令碼生成完整的 XSL-FO 文件並將其呈現為 PDF。我們使用 XSLT 來轉換表格,然後將該 XSL-FO 片段嵌入 XSL-FO 主模板中,然後將其呈現為 PDF 並流式傳輸二進位制文件。當然,還有其他方法來組裝完整的 XSLT-FO 文件。

xquery version "1.0";
import module namespace xslfo="http://exist-db.org/xquery/xslfo";
import module namespace transform="http://exist-db.org/xquery/transform";
declare namespace fo="http://www.w3.org/1999/XSL/Format";

let $table :=
<table heading="Department Phone Extensions">
    <Person>
        <Name>John Doe</Name>
        <Extension>1234</Extension>
    </Person>
    <Person>
        <Name>Doe John</Name>
        <Extension>4321</Extension>
    </Person>
    <Person>
        <Name><span style="color: #f00;">Sue Smith</span></Name>
        <Extension>5678</Extension>
    </Person>
</table>

let $table-fo := transform:transform($table,doc("/db/Wiki/eXist/xsl-fo/table2fo.xsl"),())
let $fo := 
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="my-page">
                    <fo:region-body margin="1in"/>
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="my-page">
                <fo:flow flow-name="xsl-region-body">
                    <fo:block>
                        {$table-fo}
                    </fo:block>
                </fo:flow>
            </fo:page-sequence>
      </fo:root>
   
let $pdf := xslfo:render($fo, "application/pdf", ())
return 
  response:stream-binary($pdf, "application/pdf", "output.pdf")

執行

資料庫資料

[編輯 | 編輯原始碼]

作為另一個示例,以下 XQuery 選擇所有員工並將它們呈現為 PDF 表格

xquery version "1.0";
import module namespace xslfo="http://exist-db.org/xquery/xslfo";
import module namespace transform="http://exist-db.org/xquery/transform";
declare namespace fo="http://www.w3.org/1999/XSL/Format";

let $table :=
<table heading="Employees">
   {//Emp}
</table>

let $table-fo := transform:transform($table,doc("/db/Wiki/eXist/xsl-fo/table2fo.xsl"),())
let $fo := 
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="my-page">
                    <fo:region-body margin="1in"/>
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="my-page">
                <fo:flow flow-name="xsl-region-body">
                    <fo:block>
                        {$table-fo}
                    </fo:block>
                </fo:flow>
            </fo:page-sequence>
      </fo:root>
   
let $pdf := xslfo:render($fo, "application/pdf", ())
return 
  response:stream-binary($pdf, "application/pdf", "output.pdf")

執行

華夏公益教科書