You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

exist-DB标签生成失败:序列化节点集权限拒绝问题求助

解决eXist-DB标签打印功能的权限错误及代码问题

我是一名数字档案管理员,刚入职新机构。机构核心eXist-DB数据库1.5-2年前宕机,目前已完成恢复,仅打印箱/文件夹标签的功能无法正常运行。执行时抛出权限错误,相关XQuery代码及错误信息如下:

ERROR Cannot serialize file. A problem occurred while serializing the node set: ../Boxes-.xml (Permission denied) [at line 66, column 33] In function: arc3:view(item()*) [25:27:/db/apps/archives3/modules/arc3.xql]

相关XQuery代码

declare function arc3:view($form) as xs:string* 
{
(:  let $real-user1 := session:get-attribute("user")
    let $real-password := session:get-attribute("password") 
    let $new := session:set-current-user($real-user1, $real-password)
:)  

    let $s := arc3log:add-log-message("at top of local view")
    let $file-name := $form/data/file
    let $short-name := $form/data/shortTitle

(:  let $current := xmldb:get-current-user()
    let $temp := concat($current,"-temp-file.xml")
    let $d := xmldb:store("/db/apps/archives3/data/", $temp, $form)
    let $tempFile := concat("/db/apps/archives3/data/",$temp)
    let $rec := util:eval("doc($tempFile)")  
:)  
    let $rec := $form
  
    let $rec := transform:transform($rec, "xmldb:exist:///apps/archives3/resources/styles/printLabel.xsl", <parameters><param name="filename" value="{$file-name}"/></parameters>)

    let $query := if($form/data/type='folder') then concat($rec, "order by number($f/did/container[@type='box']),number($f/did/container[@type='folder']) return <folder><box>{$f/did/physloc/text()}</box><folderNumber>{$f/did/container[@type='folder']/text()}</folderNumber><folderTitle>{$f/did/unittitle/text()}</folderTitle><date1>{$f/did/unitdate/text()}</date1><Accession>{$f/acqinfo/p/num/text()}</Accession><Title>{$f/ancestor::ead/archdesc/did/unittitle[@type='short']/text()}</Title></folder>") else concat($rec,") order by number($boxes) return    for $box in $boxes      let $date2 := if (doc('",$file-name,"')/ead//dsc//container[.[@type='box'] = $box]/../unitdate/string-length(@normal) > 4) then  max(doc('",$file-name,"')/ead//dsc//container[.[@type='box'] = $box]/../unitdate/substring(@normal,6)) else max(doc('",$file-name,"')/ead//dsc//container[.[@type='box'] = $box]/../unitdate/substring(@normal,1,4))
                        
                        
    let $date3 := min(doc('",$file-name,"')/ead//dsc//container[.[@type='box'] = $box]/../unitdate/substring(@normal,1,4))  let $f := doc('",$file-name,"')/ead//dsc//container[.[@type='box'] = $box][1]   let $d := doc('",$file-name,"')/ead//dsc//container[.[@type='box'] = $box][last()]  let $line := $f/ancestor::c[@level='series']/did/unittitle/text()   let $line2 := $d/ancestor::c[@level='series']/did/unittitle/text()  let $test1 := if ($date3=$date2)                     then <date>{$date2}</date>                 else <date>{$date3}-{$date2}</date>     let $test2 := if ($line=$line2) then <line>{$line}</line>   else <line>{$line}-{$line2}</line>  return <box><accession>{$f/../../acqinfo/p/num/text()}</accession><fonds><name>{$f/ancestor::archdesc/did/origination/text()}</name></fonds>            <title><prime>{$f/ancestor::archdesc/did/unittitle[1]/text()}</prime>{$test2} {$test1} </title> <container>{$d/text()}</container> <stack>{$f/../physloc/text()}</stack></box>") 
 
    let $s := arc3log:add-log-message("did transform")

    let $query := if($form/data/type='box' and contains($rec,'physloc')) then  concat($rec, ") order by number($boxes)
return  
for $box in $boxes      
let $date2 := if(max(doc('",$file-name,"')/ead//dsc//physloc[. = $box]/../unitdate/string-length(@normal) > 5)       then max(doc('",$file-name,"')/ead//dsc//physloc[. = $box]/../unitdate/substring(@normal,6)) else max(doc('",$file-name,"')/ead//dsc//physloc[. = $box]/../unitdate/substring(@normal,-1,4)) 
let $date3 := min(doc('",$file-name,"')/ead//dsc//physloc[. = $box]/../unitdate/substring(@normal,1,4)) 
let $f := doc('",$file-name,"')/ead//dsc//physloc[. = $box]/../container[@type='box'][1]
let $d := doc('",$file-name,"')/ead//dsc//physloc[. = $box]/../container[@type='box'][last()] 
let $line := $f/ancestor::c[@level='series']/did/unittitle/text() 
let $line2 := $d/ancestor::c[@level='series']/did/unittitle/text() 

let $test1 := if ($date3=$date2) then <date>{$date2}</date> else <date>{$date3}-{$date2}</date>
let $test2 := if ($line=$line2) then <line>{$line}</line> else <line>{$line}-{$line2}</line>

return <box><accession>{$f/../../acqinfo/p/num/text()}</accession><fonds><name>{$f/ancestor::archdesc/did/origination/text()}</name></fonds>            <title><prime>{$f/ancestor::archdesc/did/unittitle[1]/text()}</prime>{$test2} {$test1} </title> <container>{$d/text()}</container> <stack>{$f/../physloc/text()}</stack></box>") else $query



    let $s := arc3log:add-log-message(concat("this Query is: ", $query))
    
    let $recs := util:eval($query)
    let $s := arc3log:add-log-message(concat("this result is: ", $recs))    
    
    let $blank-label := if ($form/data/type="folder") then <folder xmlns="" /> else <box xmlns="" />

    let $count := $form/data/startLabel
    let $add := (
      for $p in 1 to (xs:int($count)-1)
       return $blank-label
        )
    
    let $label :=   if($form/data/type ="folder" ) then
                    <FLD xmlns="">{$add} { $recs} </FLD>
                else 
                    <boxlbl xmlns="">{$add}{$recs}</boxlbl>  
                    
    let $s := arc3log:add-log-message(concat("the label is: ", $label))

    let $s := if ($form/data/type ="folder") then file:serialize($label,concat("../Labels-",$short-name,".xml"), "method=xml, omit-xml-declaration=no, media-type=application/xml, indent=no") 
                else 
                file:serialize($label, concat("../Boxes-",$short-name,".xml"),"method='xml',omit-xml-declaration='no',media-type='application/xml',indent='no'") 

    return
        if ($form/data/type ="folder") then 
            concat("Labels-",$form/data/shortTitle,".xml")
        else 
            concat("Boxes-",$form/data/shortTitle,".xml")
             
    
};

问题分析与修复步骤

1. 解决权限错误

错误提示里的../Boxes-.xml暴露两个问题:

  • 路径../指向eXist-DB安装目录的上级目录,eXist运行用户默认没有该目录的写入权限
  • 文件名出现Boxes-.xml,说明$short-name变量为空,导致拼接出无效文件名

修复措施:

  • 更换存储路径:将输出目录改为eXist允许写入的位置,比如数据库内的应用目录/db/apps/archives3/labels/,或者eXist配置的本地可写目录(如exist-data/labels/)
  • 处理空文件名:给$short-name添加默认值,避免生成无效文件名:
    let $short-name := if (exists($form/data/shortTitle) and string-length($form/data/shortTitle) > 0) 
                       then $form/data/shortTitle 
                       else "unnamed"
    

2. 修复XQuery语法错误

代码中存在多处字符串拼接错误,会导致util:eval执行失败:

  • 动态拼接的XQuery语句里,doc('",$file-name,"')的引号嵌套错误,正确写法应该是用字符串拼接连接文件名:
    concat($rec, ") order by number($boxes) return for $box in $boxes let $date2 := if (doc('", $file-name, "')/ead//dsc//container[.[@type='box'] = $box]/../unitdate/string-length(@normal) > 4) then max(doc('", $file-name, "')/ead//dsc//container[.[@type='box'] = $box]/../unitdate/substring(@normal,6)) else max(doc('", $file-name, "')/ead//dsc//container[.[@type='box'] = $box]/../unitdate/substring(@normal,1,4))")
    
  • 所有动态拼接的XQuery语句都要确保引号正确闭合,避免语法错误

3. 优化代码安全性与稳定性

  • 避免使用util:eval:动态拼接XQuery并执行存在注入风险,建议重构代码,直接用XQuery表达式处理数据,而非拼接字符串后执行
  • 校验startLabel有效性:确保它是合法整数,避免转换错误:
    let $count := if (exists($form/data/startLabel) and $form/data/startLabel castable as xs:int) 
                  then xs:int($form/data/startLabel) 
                  else 1
    

内容的提问来源于stack exchange,提问作者DigiArch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 07:13:15