跳轉到內容

XQuery/DocBook 到 Microsoft Word

來自華夏公益教科書,開放的書籍,開放的世界

您想要從 DocBook 檔案建立 Microsoft Word 文件。

構建高質量的 DocBook 到 MS-Word .docx 轉換有兩個步驟。

  1. 建立一個 docx 生成器,該生成器使用所有正確元件組裝一個 zip 檔案
  2. 建立一個型別切換轉換,將每個 DocBook 元素轉換為相應的 Open Office XML 格式

在這篇文章中,我們將使用 Microsoft Open_Packaging_Conventions (OPC) 格式建立 zip 檔案。OPC 檔案可以使用任何桌面解壓縮程式開啟,但必須以程式設計方式建立,以確保特定檔案放置在正確的順序。我們將建立幾個小的 XQuery 函式,這些函式將從輸入 DocBook 5 檔案中提取關鍵元素,並生成 Open Office XML 規範中使用的 XML 檔案。然後,我們將使用單個 generate-docx() 函式將所有元件組裝到一個 zip 檔案中。


另一個轉換將遵循非常相似的模式。

Zip 檔案生成

[編輯 | 編輯原始碼]

本節向您展示使用 XQuery 生成 zip 檔案的過程。這取決於您是否擁有一個 zip 函式,該函式允許您指定輸出檔案的每個元件,並且專門要求輸出按文件順序排列。

輸出檔案配置

[編輯 | 編輯原始碼]

輸出是一個 zip 檔案,包含以下內容

  • [Content_Types].xml - 根目錄中的單個 XML 檔案。此檔案必須放在 zip 檔案集合中的第一位。
  • _rels - 一個資料夾,其中包含單個.rels檔案,該檔案是一個包含檔案之間關係的 XML 檔案
  • docProps - 一個包含文件屬性檔案的資料夾。這些通常是 app.xml 和 core.xml 檔案
  • word - 一個包含所有 word 內容和兩個子資料夾的資料夾。典型內容包括
    • _rels 資料夾,其中包含單個檔案,例如 document.xml.rels
    • theme 資料夾,其中包含單個檔案,例如 theme1.xml
    • document.xml
    • fontTable.xml
    • settings.xml
    • styles.xml
    • webSettings.xml

Zip 函式示例使用

[編輯 | 編輯原始碼]

compression:zip( $entries, true() ) 函式接受兩個引數。第一個是一系列<entries>元素,每個元素代表我們要建立的每個檔案或集合。

以下是構建主[Content_Types].xml檔案的條目。

<entry name="[Content_Types].xml" type="xml" method="store">{doc(concat($db2docx:template-collection, '/content-types-template.xml'))}</entry>

以下是如何將檔案放在 _rels 資料夾中並使用 .rels 檔名的示例

<entry name="_rels/.rels" type="xml" method="store">{doc(concat($db2docx:template-collection, '/dot-rels.xml'))}</entry>

因此,為了構建 docx 檔案,我們使用 compression:zip() 函式“組裝”每個<entry>元素,然後使用正確的 MIME 型別和檔名將二進位制流返回到 Web 瀏覽器。此檔案將被下載,然後您就可以使用 MS Word 開啟它。

declare function db2docx:generate-docx($docbook-input-document as node(), $filename as xs:string) {

(: this has a sequence of <entry> elements that is used by the zip function :)
    let $entries :=
        (
        db2docx:content-type-entry(),
        ...
        db2docx:root-rels())
    return
        (
        response:set-header("Content-Disposition", concat("attachment; filename=", concat($filename, '.docx')))
        ,
        response:stream-binary(
            compression:zip( $entries, true() ),
            'application/zip',
            concat($filename, '.docx')
            )
        )
};

將 DocBook 5 元素對映到 Open Office XML

[編輯 | 編輯原始碼]

DocBook 檔案非常易於使用,因為整個文件可以儲存在一個檔案中。DocX 有許多小檔案,這些檔案儲存在 zip 存檔中的許多不同位置。

以下是一些示例

核心屬性

[編輯 | 編輯原始碼]

核心屬性元素是您可能在書籍或文章的書目條目中看到的標準Dublin Core 元資料元素。

<cp:coreProperties xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <!-- Dublin Core Metadata Elements -->
    <dc:title>Converting DocBook to DocX Format</dc:title>
    <dc:subject>Horror Stories</dc:subject>
    <dc:creator>Dan McCreary</dc:creator>
    <cp:keywords>XML, Docbook, DocX, Conversion, Transformation, TypeSwitch</cp:keywords>
    <dc:description>How to convert DocBook to DocX</dc:description>
    <cp:lastModifiedBy>Dan McCreary</cp:lastModifiedBy>
    <cp:revision>1</cp:revision>
    <dcterms:created xsi:type="dcterms:W3CDTF">2012-05-04T13:35:00Z</dcterms:created>
    <dcterms:modified xsi:type="dcterms:W3CDTF">2012-05-04T13:35:00Z</dcterms:modified>
</cp:coreProperties>

應用程式屬性

[編輯 | 編輯原始碼]

以下是一個 XQuery 函式示例,該函式將填充應用程式屬性 XML 檔案中的節數。

declare function db2docx:app-properties($docbook-input-document as node()) {
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" 
   xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
    <SectionCount>{count($docbook-input-document//sect1)}</SectionCount>
    <Application>DocBook 5 to Microsoft Open Office XML (DocX) Converter by Dan McCreary of Kelly-McCreary &amp; Associates</Application>
    <DocSecurity>0</DocSecurity>
    <Lines>1</Lines>
    <Paragraphs>1</Paragraphs>
    <ScaleCrop>false</ScaleCrop>
    <Company>Kelly-McCreary &amp; Associates</Company>
    <LinksUpToDate>false</LinksUpToDate>
    <CharactersWithSpaces>12</CharactersWithSpaces>
    <SharedDoc>false</SharedDoc>
    <HyperlinksChanged>false</HyperlinksChanged>
    <AppVersion>0.1</AppVersion>
</Properties>
};

文件主體元素轉換

[編輯 | 編輯原始碼]

將您的 DocBook 元素對映到 Open Office XML 格式將根據您使用的 DocBook 元素以及 Word 模板結構而有所不同。本教程示例將演示以下元素的對映

  1. article
  2. article title
  3. sect1
  4. sect 1 title
  5. para
  6. figure

DocBook 5 輸入檔案示例

[編輯 | 編輯原始碼]

我們將從一個 DocBook 5 章開始,它有兩個級別 1 節,每個節有兩個級別 2 子節,每個子節有兩個段落。

<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0">
    <title>Chapter Title</title>
    <subtitle>Chapter Subtitle</subtitle>
    <para>This is the body introductory text of the chapter</para>
    <sect1>
        <title>Level 1 Title 1</title>
        <subtitle>Section 1 Subtitle</subtitle>
        <para>This is the text of the first paragraph of the first level 1 article section.</para>
        <para>This is the text of the second paragraph of the first level 1 article section.</para>
        <sect2>
            <title>Level 2 Title 1.1</title>
            <para>This is the text of the first paragraph of the first level 2 article sub-section.</para>
            <para>This is the text of the second paragraph of the first level 2 article sub-section.</para>
        </sect2>
        <sect2>
            <title>Level 2 Title 1.2</title>
            <para>This is the text of the first paragraph of the second level 2 article sub-section.</para>
            <para>This is the text of the second paragraph of the second level 2 article sub-section.</para>
        </sect2>        
    </sect1>
    <sect1>
        <title>Level 1 Title 2</title>
        <subtitle>Section 1 Subtitle</subtitle>
        <para>This is the text of the first paragraph of the first level 1 article section.</para>
        <para>This is the text of the second paragraph of the first level 1 article section.</para>
        <sect2>
            <title>Section 2 Title 2.1</title>
            <para>This is the text of the first paragraph of the first level 2 article sub-section.</para>
            <para>This is the text of the second paragraph of the first level 2 article sub-section.</para>
        </sect2>
        <sect2>
            <title>Section 2 Title 2.2</title>
            <para>This is the text of the first paragraph of the second level 2 article sub-section.</para>
            <para>This is the text of the second paragraph of the second level 2 article sub-section.</para>
        </sect2>
        
    </sect1>
</chapter>

文件主體

[編輯 | 編輯原始碼]

Open Office XML 使用複雜的 XML 結構來儲存文字主體。段落被分解為“執行”,然後在這些執行元素中包含文字。以下結構是示例

<w:document xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" 
    xmlns:o="urn:schemas-microsoft-com:office:office" 
    xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" 
    xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" 
    xmlns:w10="urn:schemas-microsoft-com:office:word" 
    xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
    xmlns:v="urn:schemas-microsoft-com:vml" 
    xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" 
    xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006">
    <w:body>
        <w:p>
            <w:r>
                <w:t>Hello World!</w:t>
            </w:r>
        </w:p>
    </w:body>
</w:document>

建立您的 Typeswitch 轉換

[編輯 | 編輯原始碼]

現在我們準備深入研究元素逐元素的轉換。

結構如下

declare function db2docx:main($content as node()*) as item()* {
    for $node in $content
    (: let $log := util:log-system-out(concat('In main with ', count($node//node()), ' elements')) :)
    return 
        typeswitch($node)
            case text() return $node
            
            (:
            case element(article) return db2h:article($node)
            case element(book) return db2h:book($node) :)

            (: each of these is responsible for handling its own title, paragraphs and subsections :)
            case element(db:chapter) return db2docx:chapter($node)
            case element(db:sect1) return db2docx:sect1($node)
            case element(db:sect2) return db2docx:sect2($node)
....
           default return db2docx:null()
};

將您的 DocBook 元素對映到 Open Office XML 格式將根據您使用的 DocBook 元素以及 Word 模板結構而有所不同。本教程示例將演示以下元素的對映

  1. article
  2. article title
  3. sect1
  4. sect 1 title
  5. para
  6. figure
  7. 等等

遞迴函式示例

[編輯 | 編輯原始碼]

主要“排程”函式將到達每個高階元素的節點。然後它將轉到專門與該元素相關的函式。通常,函式名稱與元素名稱相同。

在轉換的每個級別,您都輸入了需要的元素資料,然後為每個子元素呼叫主函式。這使您可以專門輸入已知存在的結構,並避免必須根據您在樹中的位置查詢元素的上下文。例如,標題元素在章、sect1 和 sect2 節中始終使用。當您到達標題元素時,您可以查詢父元素名稱,但通常更容易在剛到達的節中輸入元素。

declare function db2docx:sect1($sect1 as node()) as node()* {
(
    <!-- sect1 -->,
    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading1"/>
        </w:pPr>
        <w:r>
            <w:t>{$sect1/db:title/text()}</w:t>
        </w:r>
    </w:p>,
    db2docx:main($sect1/db:para),
    db2docx:main($sect1/db:sect2)
)
};

輸出示例

[編輯 | 編輯原始碼]
Screen Image
螢幕影像

新增影像

[編輯 | 編輯原始碼]

DocBook 圖表

[編輯 | 編輯原始碼]

DocBook 圖表具有以下示例結構

<figure>
   <title>Figure Caption</title>
   <mediaobject>
      <imageobject>
           <imagedata fileref="images/my-image.png" scale="50" contentwidth="500"/>
      </imageobject>
   </mediaobject>
</figure>

在上面的示例中,我們將所有文章的圖片儲存在 images 集合中,直接儲存在儲存主文章 XML 檔案的集合中。我們還將圖片縮放到原始尺寸的 50% 或將內容寬度設定為固定畫素數。

Open Office 圖片示例

[編輯 | 編輯原始碼]

以下是 docx 格式圖片的等效結構

<w:drawing>
    <wp:inline distT="0" distB="0" distL="0" distR="0">
        <wp:extent cx="1714286" cy="514286"/>
        <wp:effectExtent l="19050" t="0" r="214" b="0"/>
        <wp:docPr id="1" name="Picture 0" descr="nosql-logo.png"/>
        <wp:cNvGraphicFramePr>
            <a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
               noChangeAspect="1"/>
        </wp:cNvGraphicFramePr>
        <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
            <a:graphicData
                uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                <pic:pic
                    xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                    <pic:nvPicPr>
                        <pic:cNvPr id="0" name="my-image-file.png"/>
                        <pic:cNvPicPr/>
                    </pic:nvPicPr>
                    <pic:blipFill>
                        <a:blip r:embed="rId4" cstate="print"/>
                        <a:stretch>
                            <a:fillRect/>
                        </a:stretch>
                    </pic:blipFill>
                    <pic:spPr>
                        <a:xfrm>
                            <a:off x="0" y="0"/>
                            <a:ext cx="1714286" cy="514286"/>
                        </a:xfrm>
                        <a:prstGeom prst="rect">
                            <a:avLst/>
                        </a:prstGeom>
                    </pic:spPr>
                </pic:pic>
            </a:graphicData>
        </a:graphic>
    </wp:inline>
</w:drawing>

二進位制圖片必須放置在 word/media 集合中。

修訂識別符號 (RSIDS)

[編輯 | 編輯原始碼]

Microsoft 文件還為每個段落、執行和文字包含大量的修訂屬性或“RSIDS”。當有多個作者進行更改並且需要使用修訂審閱系統跟蹤更改時,會使用這些屬性。透過為文字的每個元件分配隨機 ID 號,可以更方便地檢視跟蹤的更改。

<w:p w:rsidR="00D910F7" w:rsidRDefault="00CB02EF" w:rsidP="00CB02EF">
   <w:pPr>
      <w:pStyle w:val="Title"/>
   </w:pPr>
      <w:r>
         <w:t>Document Title</w:t>
      </w:r>
</w:p>
<w:p w:rsidR="00CB02EF" w:rsidRDefault="00CB02EF" w:rsidP="00CB02EF">
   <w:pPr>
      <w:pStyle w:val="Heading1"/>
         </w:pPr>
      <w:r>
         <w:t>I am heading</w:t>
      </w:r>
</w:p>
<w:p w:rsidR="00CB02EF" w:rsidRDefault="00CB02EF">
   <w:r>
      <w:t>This is the body text for a paragraph.</w:t>
   </w:r>
</w:p>

您可以透過轉到 Microsoft Word 選項,然後轉到信任中心,然後選擇“隱私設定”(儘管這與隱私無關)並取消選中“儲存隨機數以提高合併準確性”來停用 RSIDS 的生成。

參考文獻

[編輯 | 編輯原始碼]
華夏公益教科書