Search code examples
xmlxquerymarklogicexist-db

Evaluate a string in an XQuery function while maintaining context


In marklogic, how can I evaluate a string (using xdmp:value(), xdmp:eval(), or ??) in a function and maintain still maintain context? (I'm able to do this in eXist with util:eval-inline().)

Here's an example of what I'm talking about.

XQuery

let $predicate := "val='1234'"
let $xml :=
    <doc>
        <test>
            <val>abcd</val>
        </test>
        <test>
            <val>1234</val>
        </test>
    </doc>

return $xml/test[xdmp:value($predicate)]

Output (which is what I wanted/expected):

<test>
  <val>1234</val>
</test>

The issue I'm having is when I try to put xdmp:value() in a function:

XQuery

declare function local:value($string as xs:string) as item()* {
  xdmp:value($string)
};

let $predicate := "val='1234'"
let $xml :=
    <doc>
        <test>
            <val>abcd</val>
        </test>
        <test>
            <val>1234</val>
        </test>
    </doc>

return $xml/test[local:value($predicate)]

This returns the following error:

[1.0-ml] XDMP-MISSINGCONTEXT: (err:XPDY0002) val -- Missing context item

I'm able to do this in eXist (below); is it possible to do this in marklogic? I'm also trying to keep the local function signatures the same.

XQuery (works in eXist)

declare function local:value($string as xs:string) as item()* {
  util:eval-inline(.,$string)
};

let $predicate := "val='1234'"
let $xml :=
    <doc>
        <test>
            <val>abcd</val>
        </test>
        <test>
            <val>1234</val>
        </test>
    </doc>

return
    $xml/test[local:value($predicate)]

Output (which is what I wanted/expected):

<test>
  <val>1234</val>
</test>

Solution

  • I think you'd have to pass the context node to your function.

    declare function local:value($context as node(), $string as xs:string)
    as item()*
    {
      $context/xdmp:value($string)
    };
    
    let $predicate := "val='1234'"
    let $xml :=
      <doc>
            <test>
                <val>abcd</val>
            </test>
            <test>
                <val>1234</val>
            </test>
        </doc>
    return $xml/test[local:value(., $predicate)]
    

    Or just:

    let $predicate := "val='1234'"
    let $xml :=
      <doc>
            <test>
                <val>abcd</val>
            </test>
            <test>
                <val>1234</val>
            </test>
        </doc>
    return $xml/test[xdmp:value($predicate)]
    

    Both of those work for me with 7.0-2.3

    <test>
      <val>1234</val>
    </test>