跳转到内容

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)
华夏公益教科书