XQuery/DocBook 到 Microsoft Word
您想要從 DocBook 檔案建立 Microsoft Word 文件。
構建高質量的 DocBook 到 MS-Word .docx 轉換有兩個步驟。
- 建立一個 docx 生成器,該生成器使用所有正確元件組裝一個 zip 檔案
- 建立一個型別切換轉換,將每個 DocBook 元素轉換為相應的 Open Office XML 格式
在這篇文章中,我們將使用 Microsoft Open_Packaging_Conventions (OPC) 格式建立 zip 檔案。OPC 檔案可以使用任何桌面解壓縮程式開啟,但必須以程式設計方式建立,以確保特定檔案放置在正確的順序。我們將建立幾個小的 XQuery 函式,這些函式將從輸入 DocBook 5 檔案中提取關鍵元素,並生成 Open Office XML 規範中使用的 XML 檔案。然後,我們將使用單個 generate-docx() 函式將所有元件組裝到一個 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
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 檔案非常易於使用,因為整個文件可以儲存在一個檔案中。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 & Associates</Application>
<DocSecurity>0</DocSecurity>
<Lines>1</Lines>
<Paragraphs>1</Paragraphs>
<ScaleCrop>false</ScaleCrop>
<Company>Kelly-McCreary & 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 模板結構而有所不同。本教程示例將演示以下元素的對映
- article
- article title
- sect1
- sect 1 title
- para
- figure
我們將從一個 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>
現在我們準備深入研究元素逐元素的轉換。
結構如下
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 模板結構而有所不同。本教程示例將演示以下元素的對映
- article
- article title
- sect1
- sect 1 title
- para
- figure
- 等等
主要“排程”函式將到達每個高階元素的節點。然後它將轉到專門與該元素相關的函式。通常,函式名稱與元素名稱相同。
在轉換的每個級別,您都輸入了需要的元素資料,然後為每個子元素呼叫主函式。這使您可以專門輸入已知存在的結構,並避免必須根據您在樹中的位置查詢元素的上下文。例如,標題元素在章、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)
)
};

DocBook 圖表具有以下示例結構
<figure>
<title>Figure Caption</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/my-image.png" scale="50" contentwidth="500"/>
</imageobject>
</mediaobject>
</figure>
在上面的示例中,我們將所有文章的圖片儲存在 images 集合中,直接儲存在儲存主文章 XML 檔案的集合中。我們還將圖片縮放到原始尺寸的 50% 或將內容寬度設定為固定畫素數。
以下是 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 集合中。
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 的生成。