Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use user defined function in Xquery to replace node value in PLSQL?

I want to change oracle xmltype node value by my function my_calculator but I can't. See there:

set serveroutput on
declare
w_xml xmltype;
begin

SELECT
      XMLQUERY('copy $tmp := .
               modify
                (for $l3 in $tmp//Line3
                    return replace value of node $l3 with my_calculator($l3)
                )
                
                return $tmp'
               PASSING xmltype('<Response><Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>10</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
  <Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>12</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
</Response>') RETURNING CONTENT)
        into w_xml
        FROM dual;
        dbms_output.put_line( w_xml.extract('/*').getClobVal() );
end;

It return:

Error report -
ORA-19237: XPST0017 - unable to resolve call to function - fn:my_calculator
ORA-06512: at line 5
19237. 00000 -  "XPST0017 - unable to resolve call to function - %s:%s"
*Cause:    The name and arity of the function call given could not be matched with any in-scope function in the static context.
*Action:   Fix the name of the function or the number of parameters to match the list of in-scope functions.

Can I use a user's function in "return replace value of node $l3 with my_calculator($l3)" ? Many thanks.

like image 907
oldnewdb Avatar asked Aug 15 '26 09:08

oldnewdb


1 Answers

You can't call pl/sql functions in xpath and xquery. They have own functions and operators: https://www.w3.org/TR/xpath-functions-31/ But you can declare and use own xquery function:

SELECT
      XMLQUERY('declare function local:my_calculator($p) {xs:decimal($p + 100)}; (: eof :)
      copy $tmp := .
               modify
                (for $l3 in $tmp//Line3
                    return replace value of node $l3 with (local:my_calculator($l3))
                )
                return $tmp'
               PASSING xmltype('<Response><Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>10</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
  <Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>12</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
</Response>') RETURNING CONTENT) as xdata
FROM dual;

Results:

XDATA
----------------------------------------------------------------------------------------------------
<Response>
  <Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>110</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
  <Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>112</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
</Response>

But in this simple case you don't even need PL/SQL functions, just use simple operators:

SELECT
      XMLQUERY('copy $tmp := .
               modify
                (for $l3 in $tmp//Line3
                    return replace value of node $l3 with (xs:integer($l3) + 100)
                )
                
                return $tmp'
               PASSING xmltype('<Response><Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>10</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
  <Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>12</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
</Response>') RETURNING CONTENT) as xdata
FROM dual;

Results:

XDATA
----------------------------------------------------------------------------------------------------
<Response>
  <Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>110</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
  <Card>
    <Address attr_cust="0">
      <Line2>def</Line2>
      <Line3>112</Line3>
      <Line4>jkl</Line4>
      <Line5>mno</Line5>
      <Country/>
    </Address>
  </Card>
</Response>
like image 63
Sayan Malakshinov Avatar answered Aug 17 '26 05:08

Sayan Malakshinov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!