Xml 如何将属性添加到节点的所有特定子级

Xml 如何将属性添加到节点的所有特定子级,xml,xquery,marklogic,Xml,Xquery,Marklogic,我有以下节点,我想在其中向所有add节点添加属性 <test> <add>x1</add> <c><add>x2</add></c> <b att1="x">x</b> </test> 它可以将属性添加到test节点。但是 当我试着 functx:add-attributes($test/add, xs:QName('att1'), 1) 它将属性添加到第一个添

我有以下节点,我想在其中向所有
add
节点添加属性

<test>
  <add>x1</add>
  <c><add>x2</add></c>
  <b att1="x">x</b>
</test>
它可以将属性添加到
test
节点。但是

当我试着

functx:add-attributes($test/add, xs:QName('att1'), 1)
它将属性添加到第一个添加节点,但仅返回添加了属性的添加节点。然后,当我尝试使用
$test//add
时,它抛出错误

当我试着

for $add in $test//add 
   return functx:add-attributes($add, xs:QName('att1'), 1)

它分别返回两个add节点。现在,如何重新构造原始节点以仅将属性添加到指定节点。

首先,让我指出,仅在内存中使用与更新数据库内容的方式有所不同。对于后者,您可以执行以下操作:

for $add in $test//add
return
  xdmp:node-insert-child(
    $add, 
    attribute atta1 { 1 }
  )
要在内存中更改它(functx就是这么做的),您需要复制原始文件,并在构建副本时对其进行更改。这称为递归下降,是一种非常常见的模式。我不久前写了一篇博文,其中显示了,但本质上,您将执行一个类型切换,当遇到“add”元素时,它将创建新属性。您可以使用functx函数进行此操作。大致如下(未经测试):


此代码假定add元素内部没有add元素;如果你愿意,那么你会想做一些类似于第一个案例的第二个案例

您可以通过两种方式替换/插入/删除元素或属性。 在内存中更改或更改数据库的实际内容。 因为您不想更改数据库中的值,所以可以使用内存中的文档更新

导入模块名称空间mem=”http://xqdev.com/in-mem-update“在mem update.xqy中的“/MarkLogic/appservices/utils/at”

您可以使用
mem:node insert child(,)

我不想更改DB中的值。我想得到这个值,我想用一些自定义属性重新构造它,并将它呈现给转换。我尝试了第二种方法,但是行$node/node()!本地:更改(.)引发错误。我不确定运算符“!”的用法。这是错误“意外令牌语法错误、意外垃圾、应为逗号或Rbrace”。我试着用很多方法来改变它,但都不起作用。请回复。我也会努力让它工作。你使用的是什么版本的MarkLogic?“!”操作符相对较新。您可以在$node/node()中用
for$n替换该行返回local:change($n)
非常感谢,它成功了。在办公室里,我们使用的是ML7。我在家里试过这个样本,我刚吃过ML5。在ML7中,它正在工作。
for $add in $test//add
return
  xdmp:node-insert-child(
    $add, 
    attribute atta1 { 1 }
  )
declare function local:change($node) 
{ 
  typeswitch($node) 
    case element(add) return 
      functx:add-attributes($node, xs:QName('att1'), 1)
    case element() return 
      element { fn:node-name($node) } { 
        $node/@*, 
        $node/node() ! local:change(.)
      } 
    default return $node 
};