在使用 eXist-db 和 XQuery 存储数据之前更新内存中的节点

Update in-memory nodes before storing the data with eXist-db and XQuery

我正在使用 eXist-db 创建一个基于 Web 的数据库应用程序。 我的愿望是将用户在使用 XForms 创建的公式中插入的数据保存到数据库中。为此,整个数据结构保存在变量 $content 中,我使用这样的 XQuery 模块存储在数据库中:

declare
    %rest:PUT("{$content}")
    %rest:path("/items")
function ffdb:change-items($content as node()*) {
    let $data := <items>
            { $content/items/* }
        </items>

    let $stored := xmldb:store($config:app-root, "1234.xml", $data)

    return
        doesnotmatter:function()
};

在此示例中,$content 包含以下节点集:

<items>
    <item1>A</item>
    <item2>B</item>
    <itemlist>
        <item3>C</item3>
    <itemlist/>
<items>

效果很好。我现在的问题是,在将节点存储到数据库之前,我想在 $content/items/itemlist 中插入一个内容为 'D' 的节点。存储结果应该是:

<items>
    <item1>A</item>
    <item2>B</item>
    <itemlist>
        <item3>C</item3>
        <item3>D</item3>
    <itemlist/>
<items>

这好像比我想象的要难。我想我试过一百次更改查询。 当我尝试直接在 $content 中插入一个节点集时,我收到一条消息,指出 XQuery 更新表达式无法应用于内存中的节点。 当我在声明数据后尝试将节点集插入 $data 时,数据已存储但不幸的是没有节点集。

我也安装了 https://github.com/ryanjdew/XQuery-XML-Memory-Operations 的模块,然后在开头插入:

let $content2 := mem:copy($content) !
    ( 
    mem:insert-child(., $content/items/itemlist, attribute new-attribute {"item3"}),
    mem:execute(.))

之后,我在声明 $data 时插入了 $content2 而不是 $content。我收到的消息如下:

org.exist.xquery.XPathException: mem-op:MIXEDSOURCES The nodes to change are coming from multiple sources [at line 249, column 3, source: /db/apps/myapp/modules/memoryoperations/memory-operations-pure-xquery.xqy]

不知道该怎么办。我还尝试在存储文档后加载文档并在此处插入节点集,这样我就不会更改内存中的数据,但这也不起作用。未插入节点集。

您说得对,eXist 的 XQuery 更新工具不支持内存操作。除了身份转换(例如,使用 XSLT 或 a recursive application of XQuery's typeswitch expression,您找到的 Ryan J. Dew 库的 "pure xquery" 版本是一个可行的选择。

假设您已经下载了 https://github.com/ryanjdew/XQuery-XML-Memory-Operations 存储库,将其解压缩,并将生成的文件夹上传到 /db/apps,此代码将产生您描述的所需结果(我使用的是 eXist 3.1 .0 并在 eXide 中测试代码):

xquery version "3.1";

import module namespace mem-op="http://maxdewpoint.blogspot.com/memory-operations" at 
    "/db/apps/XQuery-XML-Memory-Operations-master/memory-operations-pure-xquery.xqy";

let $content := 
    <items>
        <item1>A</item1>
        <item2>B</item2>
        <itemlist>
            <item3>C</item3>
        </itemlist>
    </items>
let $copy := mem-op:copy($content)
let $insert := mem-op:insert-child($copy, $content/itemlist, element item3 {"D"})
return
    mem-op:execute($insert)

这个returns:

<items>
    <item1>A</item1>
    <item2>B</item2>
    <itemlist>
        <item3>C</item3>
        <item3>D</item3>
    </itemlist>
</items>