跳转到内容

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 的生成。

参考文献

[编辑 | 编辑源代码]
华夏公益教科书