eXist-db压缩:zip函数是否添加XML声明

Kev*_*own 2 xquery exist-db

我有一个XQuery函数将一组XML文件转换为HTML并压缩它们.它在每个文件上运行一个trasform来创建<entry>元素.

从该功能开始:

declare function xport:make-sources( $path as xs:string)  as item()* {
  for $article in collection(xmldb:encode-uri($path))
  let $docnum := $article/article/div[@class = 'content']/@doc/string()
  return
  <entry name="{concat($docnum,'.html')}" type='text' method='store'>
    {transform:transform($article, doc("/db/EIDO/data/edit/xsl/doc-html.xsl"), <parameters/>)}
</entry>
} ;
Run Code Online (Sandbox Code Playgroud)

鉴于输入,我运行XQuery只是向我展示转换的结果......我看到了这一点(正是我所期待的):

<entry name="LS01.html" type="text" method="store">
<html>
    <head>
        <style>
                body {
                font-family: Arial;
                }
                article img {
                width:50%;
                }
         ...
Run Code Online (Sandbox Code Playgroud)

您将注意到此条目,并且所有条目都没有XML声明.

但现在让我们把它们放在一起并将这些条目发送到压缩.这都在Web应用程序中.完整的XQuery是这样的:

xquery version "3.0";
import module namespace transform = "http://exist-db.org/xquery/transform";
declare namespace xport = "http://www.xportability.com";
declare function xport:make-sources( $path as xs:string)  as item()* {
for $article in collection(xmldb:encode-uri($path))
  let $docnum := $article/article/div[@class = 'content']/@doc/string()
  return
  <entry name="{concat($docnum,'.html')}" type='text' method='store'>
    {transform:transform($article, doc("/db/EIDO/data/edit/xsl/doc-html.xsl"), <parameters/>)}
</entry>
} ;
let $path := request:get-parameter("path", "")
let $filename := request:get-parameter("filename", "")
let $col := xport:make-sources($path)
return
  response:stream-binary(
    xs:base64Binary(compression:zip($col,true()) ),
    'application/zip',
    $filename
)
Run Code Online (Sandbox Code Playgroud)

一切正常,我得到一个ZIP文件,其中包含从XML转换为HTML的所有文档.

但是,当我查看ZIP中的实际文件时,它有:

<?xml version="1.0" encoding="UTF-8"?>
<html>
   <head>
Run Code Online (Sandbox Code Playgroud)

XML声明不适用于ZIP的任何条目.它不存在于条目列表中的任何地方(因为它不可能).但是,拉链它们的行动显然是在增加声明.我没有看到其他原因或方式.即使指定omit-xml-declaration或将XSL中的输出类型更改为text或HTML也没有区别.这当然是因为zip的条目列表如上所示,并且显示转换的声明不存在.

ZIP中的文件具有添加的XML声明,句点.

有一些解决方法吗?

joe*_*wiz 6

当zip链接<entry>元素的内容传递给compression:zip()函数时,会在查询中隐式引入XML声明.我建议使用该fn:serialize()函数显式设置序列化选项.以下示例代码显示了如何实现您描述的结果:

xquery version "3.1";

let $node := <html><head/><body><div><h1>Hello World!</h1></div></body></html>
let $serialized := serialize($node, map { "method": "xml", "indent": true(), 
    "omit-xml-declaration": true() })
let $entries := <entry name="test.html" type="text" method="store">{$serialized}</entry>
let $filename := "test.zip"
return
    response:stream-binary(
        compression:zip($entries, true()),
        'application/zip',
        $filename
    )
Run Code Online (Sandbox Code Playgroud)

/db/apps/my-app/test.xq通过将您的Web浏览器指向http:// localhost:8080/exist/apps/my-app/test.xq,将此查询保存到类似的位置并调用它将导致您的浏览器下载test.zip.打开此zip文件将显示test.html缺少XML声明的文件:

<html>
    <head/>
    <body>
        <div>
            <h1>Hello World!</h1>
        </div>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

回到基础,通过omit-xml-declaration序列化参数切换XQuery中是否存在XML声明.要为整个查询全局省略XML声明,可以将这组声明放在查询的序言中:

declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";

declare option output:method "xml";
declare option output:omit-xml-declaration "yes";
Run Code Online (Sandbox Code Playgroud)

或者,当在查询的一部分内本地序列化时,您可以将同一组参数fn:serialize作为映射传递给函数(上面的代码示例中使用的方法):

fn:serialize($node, map { "method": "xml", "omit-xml-declaration": true() } )
Run Code Online (Sandbox Code Playgroud)

(第二个选项参数也有XML语法.)

当前版本的eXist(v4.0.0)和最新版本(可能是v3.6.0左右)支持上述所有选项,并且所有版本都支持更紧凑的特定于eXist的序列化工具,使用exist:serialize表示为字符串的选项由key=value成对组成:

declare option exist:serialize "method=xml omit-xml-declaration=yes";
Run Code Online (Sandbox Code Playgroud)

您可以在conf.xml配置文件中设置eXist的默认序列化行为.可以使用上述方法覆盖conf.xml中的默认值.eXist中不同接口上的序列化行为(例如WebDAV或XML-RPC)通常遵循conf.xml中设置的默认值,但这些默认值可以基于每个接口覆盖; 例如,请参阅有关eXist WebDAV界面序列化的文档.

  • 你是巫师.我不希望它设置默认值,所以上面存在:serialize方法产生完美的结果.感谢您抽出宝贵的时间! (3认同)