我有一个 XQuery 函数可以将一组 XML 文件转换为 HTML 并将它们压缩。它在每个文件上运行一个转换以创建 元素。

从那个函数开始:

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> 
} ; 

根据输入,我运行 XQuery 以显示转换结果......我看到了这个(正是我所期望的):

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

你会注意到这个条目,它们都没有 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 
) 

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

但是,当我查看 ZIP 中的实际文件时,它具有以下内容:

<?xml version="1.0" encoding="UTF-8"?> 
<html> 
   <head> 

XML 声明不在 ZIP 的任何条目上。它不存在于条目列表中的任何地方(因为它不可能存在)。但是压缩它们的 Action 显然是在添加声明。我看不出其他原因或方式。即使指定 omit-xml-declaration 或将 XSL 中的输出类型更改为文本或 HTML 也没有任何区别。这当然是因为上面显示了 zip 的条目列表,这表明声明在转换后 不存在。

ZIP 中的文件添加了 XML 声明,句点。

是否有一些解决方法?

请您参考如下方法:

当压缩 <entry> 的内容时,XML 声明在您的查询中隐式引入。元素被传递给 compression:zip()功能。我建议使用 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 
    ) 

将此查询保存到数据库中类似 /db/apps/my-app/test.xq 的位置并通过将您的网络浏览器指向 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> 

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

declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization"; 
 
declare option output:method "xml"; 
declare option output:omit-xml-declaration "yes"; 

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

fn:serialize($node, map { "method": "xml", "omit-xml-declaration": true() } ) 

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

当前版本的 eXist (v4.0.0) 和最近的版本(可能从 v3.6.0 左右开始)支持上述所有选项,并且所有版本都支持更紧凑的 eXist-specific serialization facility。 , 使用 exist:serialize选项表示为由 key=value 组成的字符串对:

declare option exist:serialize "method=xml omit-xml-declaration=yes"; 

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


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!