Hi Andreas,

If your dynamic path is simple, you can get rid of xquery:eval and
replace it with a fold-left iteration (see the attached example). The
programmatic solution may be safer, in particular if the supplied path
may be the result of external user input.

Obviously, you’ll need to ensure in both cases that the resulting
target node is a single element node.

Cheers,
Christian


  declare function local:add-nodes1(
    $input as node(),
    $nodes as node()*,
    $path as xs:string
  ) as node() {
    $input update {
      let $target := xquery:eval($path, map { '': . })
      return insert nodes $nodes into $target
    }
  };

  declare function local:add-nodes2(
    $input as node(),
    $nodes as node()*,
    $path as xs:string
  ) as node() {
    $input update {
      let $steps := tokenize($path, '/')
      let $target := fold-left($steps, ., function($node, $name) {
        $node/*[name() = $name]
      })
      return insert nodes $nodes into $target
    }
  };

  <xml><a><b/></a></xml>
    => local:add-nodes1(<new1/>, 'a/b')
    => local:add-nodes2(<new2/>, 'a/b')





On Sun, Oct 28, 2018 at 5:19 PM Andreas Mixich <mixich.andr...@gmail.com> wrote:
>
> I just realized, that there is another, simpler way to simulate a defer XPath 
> expression. So I ended up using:
>
> declare function local:add-node(
>   $input as node()*,
>   $what as node()*
> ) as node() {
>   copy $c := $input
>   modify insert node $what into $c
>   return $c
> };
> declare function local:add-node(
>   $input as node()*,
>   $what as node()*,
>   $at-location as xs:string
> ) as node() {
>   copy $c := $input
>   modify
>     let $xpath := xquery:eval($at-location, map{"":$c})
>     return
>       insert node $what into $c/$xpath
>   return $c
> };
>
> <html></html>
>   => local:add-node((<head></head>,<body></body>))
>   => local:add-node(<title>Example Title</title>, "head")
>

Reply via email to