跳轉到內容

XQuery/解壓縮 Office Open XML docx 檔案

來自華夏公益教科書

您想要解壓縮一個 docx 檔案

我們將使用之前示例中使用的壓縮:unzip() 函式,並將處理解壓縮的本地版本傳遞給它。

docx 檔案中的一些檔名,例如 '[Content_Types].xml',不是有效的 URI。因此,必須將它們重新命名為具有有效 URI 的檔案。

這裡是一個典型的 docx 檔案中的路徑名列表

<item path="[Content_Types].xml" type="resource">Types</item>
<item path="_rels/.rels" type="resource">Relationships</item>
<item path="word/_rels/document.xml.rels" type="resource">Relationships</item>
<item path="word/document.xml" type="resource">w:document</item>
<item path="word/theme/theme1.xml" type="resource">a:theme</item>
<item path="word/settings.xml" type="resource">w:settings</item>
<item path="word/fontTable.xml" type="resource">w:fonts</item>
<item path="word/webSettings.xml" type="resource">w:webSettings</item>
<item path="docProps/app.xml" type="resource">Properties</item>
<item path="docProps/core.xml" type="resource">cp:coreProperties</item>
<item path="word/styles.xml" type="resource">w:styles</item>

請注意,建立了三個子資料夾(_rels、word 和 docProps)。XML 檔案儲存在這些檔案中。

unzip-docx 函式

[編輯 | 編輯原始碼]

以下函式用於解壓縮 docx 檔案。此函式名必須作為引數傳遞給 unzip 函式,以告訴它對每個 docx 檔案進行何種操作。

請注意,您必須從呼叫函式中傳遞引數到此函式。

unzip-docx 函式

declare function local:unzip-docx($path as xs:string, $data-type as xs:string, $data as item()?, $param as item()*) {
    if ($param[@name eq 'list']/@value eq 'true') then
        <item path="{$path}" data-type="{$data-type}"/>
    else 
        let $base-collection := $param[@name="base-collection"]/@value/string()
        let $zip-collection := 
            concat(
                functx:substring-before-last($param[@name="zip-filename"]/@value, '.'),
                '_',
                functx:substring-after-last($param[@name="zip-filename"]/@value, '.')
                ,
                '_parts/'
            )
        let $inner-collection := functx:substring-before-last($path, '/')
        let $filename := if (contains($path, '/')) then functx:substring-after-last($path, '/') else $path
        (: we need to encode the filename to account for filenames with illegal characters like [Content_Types].xml :)
        let $filename := xmldb:encode($filename)
        let $target-collection := concat($base-collection, $zip-collection, $inner-collection)
        let $mkdir := 
            if (xmldb:collection-available($target-collection)) then () 
            else xmldb:create-collection($base-collection, concat($zip-collection, $inner-collection))
        let $store := 
            (: ensure mimetype is set properly for .docx rels files :)
            if (ends-with($filename, '.rels')) then 
                xmldb:store($target-collection, $filename, $data, 'application/xml')
            else
                xmldb:store($target-collection, $filename, $data)
        return 
            <result object="{$path}" destination="{concat($target-collection, '/', $filename)}"/>
};

unzip 函式

[編輯 | 編輯原始碼]
declare function local:unzip($base-collection as xs:string, $zip-filename as xs:string, $action as xs:string) {
    if (not($action = ('list', 'unzip'))) then <error>Invalid action</error>
    else
    let $file := util:binary-doc(concat($base-collection, $zip-filename))
    let $entry-filter := util:function(QName("local", "local:unzip-entry-filter"), 3)
    let $entry-filter-params := ()
    let $entry-data := util:function(QName("local", "local:unzip-docx"), 4)
    let $entry-data-params := 
        (
        if ($action eq 'list') then <param name="list" value="true"/> else (), 
        <param name="base-collection" value="{$base-collection}"/>,
        <param name="zip-filename" value="{$zip-filename}"/>
        )
    let $login := xmldb:login('/db', 'admin', '')

    (: recursion :)
    let $unzip := compression:unzip($file, $entry-filter, $entry-filter-params, $entry-data, $entry-data-params)
    return 
        <results action="{$action}">{$unzip}</results>
};

示例驅動程式

[編輯 | 編輯原始碼]
let $collection := '/db/test/'
let $zip-filename := 'hello-world.docx'
let $action := 'unzip' (: valid actions: 'list', 'unzip' :)
return 
    local:unzip($collection, $zip-filename, $action)
華夏公益教科書