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
相关产品推荐
相关产品推荐

