xquery - 如何修改 eXist-db 中的内存文档?

标签 xquery exist-db

我想知道如何修改存储在数据库中的原始文档的内存副本。我对 update 扩展非常满意,它允许我通过文本节点搜索/替换并永久更改它们。然而,这种行为并不总是我想要的。在某些特殊情况下,我需要导出文档并即时进行细微更改。 eXist 似乎不支持 copy,我会考虑这一点。

对于永久更改,我使用:

declare function cust-utils:replace-spaces-hard($document as xs:string) as empty() {
    let $doc := doc($document)/tei:TEI
    let $match := '(^|\s| )([szkvaiouSZKVAIOU])[\s]'
    for $i in (1 to 2)
    return
        for $text in $doc//text()
        return
            update value $text[matches(., $match)] with replace($text, $match, '$1$2 ')
};

(我迭代了两次,因为 XPATH 2.0 似乎不允许在正则表达式中使用环视,并且这里的匹配有时会重叠。)

如何暂时做同样的事情?我尝试了 Datypic 中的有趣功能但它只返回特定的节点。我需要保留文档顺序。简而言之,我需要遍历文档树,替换特定字符串并按原样返回文档以供以后使用,而无需在数据库中更新它。

更新

不幸的是,这个:

declare function cust-utils:copy($input as item()*) as item()* {
    for $node in $input
    return $node
};

完全一样

declare function cust-utils:copy($input as item()*) as item()* {
for $node in $input
   return 
      typeswitch($node)
        case element()
           return
              element { name($node) } {
                for $att in $node/@*
                   return
                      attribute { name($att) } { $att }
                ,
                (: output all the sub-elements of this element recursively :)
                for $child in $node
                   return cust-utils:copy($child/node())
              }
        default return $node
};

…看起来它返回了文档节点,而没有真正的遍历。

最佳答案

eXist 的 XQuery Update 扩展将所有更新写入数据库,并且不支持内存中操作。这与 eXist 不支持的 W3C XQuery Update Facility 1.0+ 形成对比。因此,在 eXist 中,内存中更新必须使用纯 XQuery 执行,即没有正式更新工具的附加语法和功能。

对于使用 eXist 进行内存更新,传统路径是执行“身份转换”,通常使用递归typeswitch操作;请参阅 https://en.wikipedia.org/wiki/Identity_transform#Using_XQuery 。一个显示文本节点转换同时保留文档顺序的简单示例是:

xquery version "3.0";

declare function local:transform($nodes as node()*) {
    for $node in $nodes
    return
        typeswitch ($node)
        case document-node() return 
            local:transform($node/node())
        case element() return 
            element {node-name($node)} {
                $node/@*, 
                local:transform($node/node())
            }
        case text() return 
            replace($node, '[a-z]+', upper-case($node))
        (: drop comment & processing-instruction nodes :)
        default return 
            ()
};

let $node := 
    document {
        element root {
            comment { "sample document" },
            element x {
                text { "hello" },
                element y {
                    text { "there" }
                },
                text { "friend" }
            }
        }
    }
return 
    <results>
        <before>{$node}</before>
        <after>{local:transform($node)}</after>
    </results>

结果:

<result>
    <before>
        <root>
            <!-- sample document -->
            <x>hello <y>there</y> friend</x>
        </root>
    </before>
    <after>
        <root>
            <x>HELLO <y>THERE</y> FRIEND</x>
        </root>
    </after>
</result>

另一种方法是使用内存中更新模块,例如 Ryan J. Dew 的“XQuery XML Memory Operations”模块(位于 https://github.com/ryanjdew/XQuery-XML-Memory-Operations )。如果您克隆存储库(或下载存储库的 .zip 文件并解压缩)并将该文件夹上传到 eXist 的 /db 集合,则以下代码将起作用(改编自这个旧的存在打开帖子:http://markmail.org/message/pfvu5omj3ctfzrft ):

xquery version "3.0";

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

let $node := <x>hello</x>
let $copy := mem:copy($node)
let $rename := mem:rename($copy, $node, fn:QName("foo", "y"))
let $replace-value := mem:replace-value($rename, $node, "world")
return
    mem:execute($replace-value) 

结果:

<y xmlns="foo">world</y>

关于xquery - 如何修改 eXist-db 中的内存文档?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37165238/

相关文章:

json - 使用 XQuery 检查 XML 文档的命名空间前缀是否在整个文件中被重新定义

xml - XQuery [节点 ()] : The name "s" does not denote a namespace

sql - 在 SQL Server 中合并 XML

html - XQuery 和空的 HTML 标签

xpath - 使用 XPath 谓词优化 XQuery 查询

javascript - 使用 XHR 的结果重新填充 DataTables 表

java - XQuery 表达式 - 屏幕抓取 - Saxon/JTidy

xml - 使用 XSLT 展平 XML,但基于嵌套级别

java - eXist-db:使用 XML:DB API 从 Java 应用程序连接时的用户名/密码

java - 使用 XQuery 获取 XML 文件的文件名