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

MarkLogic技术问题:如何将多文档节点保存为单个XML文件

解决MarkLogic Qconsole中保存所有文档节点到单个XML文件的问题

我看你现在的问题是只能保存最后一个<record>节点到文件,核心原因有两个:一是XML要求必须有唯一的根元素,你生成的多个<record>没有被包裹在一个根节点里;二是xdmp:save的调用方式不对,没有正确把所有节点作为整体传入。

咱们一步步来调整你的代码:

1. 替换不安全的xdmp:value节点构造方式

你现在用xdmp:value拼接字符串来生成<meta>节点,这种做法存在注入风险,而且效率不高。直接用XQuery的元素构造语法更安全可靠:

(: 替换原来的local:ifx函数 :)
declare function local:ifx($mnem as xs:string, $val as node()?) as node()* {
  if(fn:exists($val)) then
    <meta name="{$mnem}" content="{$val/text()}"/>
  else ()
};

(: 替换原来的local:forx函数 :)
declare function local:forx($mnem as xs:string, $vals as node()*) as node()* {
  for $val in $vals
  return <meta name="{$mnem}" content="{$val/text()}"/>
};

2. 修正主逻辑的根元素包裹

你的$XML2016是一组<record>节点,需要把它们全部包裹在一个根元素(比如<records>)里,这样才能生成合法的XML文件。

3. 正确调用xdmp:save

xdmp:save的语法是xdmp:save($path as xs:string, $content as node()*),你之前的写法没有把内容传给它,所以只保存了空或者最后一个节点。

修改后的完整代码

(: validate condition and create meta nodes :)
declare function local:ifx($mnem as xs:string, $val as node()?) as node()* {
  if(fn:exists($val)) then
    <meta name="{$mnem}" content="{$val/text()}"/>
  else ()
};

(: Loop and create meta nodes for multiple values :)
declare function local:forx($mnem as xs:string, $vals as node()*) as node()* {
  for $val in $vals
  return <meta name="{$mnem}" content="{$val/text()}"/>
};

declare function local:ETL($nodes as node()*) as node()*{
  for $n in $nodes
  let $v_id := $n/rec:record/meta:Metadata/meta:id
  let $v_ba := 
    for $elem in $n/rec:record/meta:Metadata/meta:fundingSource
    return 
      if (fn:string-length($elem/meta:BugetCode/meta:code) = 1) then
        fn:concat("0", $elem/meta:BugetCode/meta:code)
      else
        $elem/meta:BugetCode/meta:code
  return 
    <record url="dbfeed.iadb" mimetype="text/html" last-modified="NA">
      <metadata>
        {local:ifx("id", $v_id)}
        {local:forx("ba", $v_ba)}
      </metadata>
    </record>
};

(: find all documents within a year :)
let $docs := cts:search(
  fn:doc(),
  cts:and-query((
    cts:element-value-query(xs:QName("meta:Collection"), "EDS"),
    cts:field-range-query("rd", ">=", "2016-01-01"),
    cts:field-range-query("rd", "<", "2017-01-01")
  ))
)
let $all_records := <records>{local:ETL($docs)}</records>
return xdmp:save("/output/all-data-2016.xml", $all_records)

关键修改点说明

  • 用直接元素构造替代xdmp:value:避免了字符串拼接的安全问题,同时XQuery引擎能更好地优化执行。
  • 添加<records>根元素:把所有生成的<record>节点包裹起来,生成合法的XML结构。
  • 正确传递内容给xdmp:save:将包裹后的完整XML节点作为第二个参数传入,这样就能一次性保存所有节点了。

现在你再运行这个查询,就能在/output/all-data-2016.xml里看到所有的<record>节点了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:00:20