如何遍历内存中的XML结构并替换子进程?

时间:2017-05-14 16:58:19

标签: xquery marklogic marklogic-8

说,我有一份文件 -

<something>
  <parent>
    <child>Bird is the word 1.</child>
    <child>Curd is the word 2.</child>
    <child>Nerd is the word 3.</child>
  </parent>
  <parent>
    <child>Bird is the word 4.</child>
    <child>Word is the word 5.</child>
    <child>Bird is the word 6.</child>
  </parent>
</something>  

我想遍历文档并替换“#34; Bird&#34;用&#34;狗&#34;使用XQuery和MarkLogic API。到目前为止,我能够使用以下代码实现 -

let $doc := $DOC 
  return <something>
           {for $d at $y in $doc/element()
             let $p := <parent>
                       {for $c in $d/element()
                         let $child := if(fn:matches($c, "Bird")) then(<child>{fn:replace($c, "Bird", "Dog")}</child>) else($c)
                         return $child
                       }</parent>
             return $p}
         </something>

结果是

<something>
  <parent>
    <child>Dog is the word 1.</child>
    <child>Curd is the word 2.</child>
    <child>Nerd is the word 3.</child>
  </parent>
  <parent>
    <child>Dog is the word 4.</child>
    <child>Word is the word 5.</child>
    <child>Dog is the word 6.</child>
  </parent>
</something>

如果没有嵌套for循环,我怎样才能实现这一目标?之前曾问过这个问题,但使用的是XSLT。

2 个答案:

答案 0 :(得分:4)

Write a function and use recursion. With the typeswitch expression you can check node types at each stage of recursion, and using a computed element constructor您可以使用通用模板重建每个元素,而不知道其名称:

declare function local:transform(
  $node as node()
) as node()*
{
  typeswitch ($node)
  case element() return element { node-name($node) } {
    $node/@*, 
    for $n in $node/node()
    return local:transform($n)
  }
  case text() return 
    if (matches($node, "Bird"))
    then text { replace($node, "Bird", "Dog") }
    else $node
  default return $node
};

请注意,不必使用matches显式检查,因为如果没有匹配项,replace将返回输入字符串。

答案 1 :(得分:4)

来自wst的答案看起来非常好,但是经常会问同样的问题,他们创建了一个库来使这更容易。它通常被称为内存更新库&#39;。可在此处找到改进版本:

https://github.com/ryanjdew/XQuery-XML-Memory-Operations

我认为至少可以提一下它是值得的。

HTH!