【问题标题】:Can I use user defined function in Xquery to replace node value in PLSQL?我可以在 Xquery 中使用用户定义的函数来替换 PLSQL 中的节点值吗?
【发布时间】:2020-10-01 17:30:32
【问题描述】:

我想通过我的函数 my_calculator 更改 oracle xmltype 节点值,但我不能。 见那里:

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;

返回:

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.

我可以在 "return replace value of node $l3 with my_calculator($l3)" 中使用用户函数吗? 非常感谢。

【问题讨论】:

  • 向我们展示您的函数代码文本
  • 这是一个简单的函数:创建或替换 FUNCTION my_calculator( orig_value INT) RETURN INT IS BEGIN RETURN orig_value + 100;结束;

标签: oracle plsql xmltype qxmlquery


【解决方案1】:

您不能在 xpath 和 xquery 中调用 pl/sql 函数。他们有自己的功能和运营商:https://www.w3.org/TR/xpath-functions-31/ 但是你可以声明和使用自己的 xquery 函数:

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;

结果:

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>

但在这种简单的情况下,您甚至不需要 PL/SQL 函数,只需使用简单的运算符:

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;

结果:

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>

【讨论】:

  • 谢谢。但是我们想使用函数来转换数据。我想我会在多个节点上使用 updatexml 函数。
  • 明天Ping我,我会告诉你另一种方法如何使用pl/sql函数替换节点
  • 你能给我发个例子吗?
【解决方案2】:

因为我不能在 xquery 中使用用户函数。所以我把我的代码改成使用updatexml,如果数据不是太大并且数据库版本在11,12,它会运行正常:

create or replace FUNCTION fn_xmlupdate( var_xpath VARCHAR2, var_rec XMLTYPE,var_attribute varchar2 default 'text()') RETURN XMLTYPE
IS
v_return xmltype;
querystring varchar2(4000);
update_xquery varchar2(200):='$i/text()';
update_query clob;

BEGIN
if  var_attribute!= 'text()' then
    update_xquery:='$i/attribute::*';
end if;
querystring:='for $i in $doc'||var_xpath||'/descendant-or-self::*
            let $path := $i/string-join(ancestor-or-self::*/name(.), ''/'')
            return <data>{attribute path {concat($path,if (exists($i/attribute::*/name(.))) then 
            concat("[@",$i/attribute::*/name(.),"=",$i/attribute::*,"]","/'||var_attribute||'") else())}, attribute value {'||update_xquery||'}}</data>' ;
            
--dbms_output.put_line(querystring);

select --listagg(path_value,',') within group (order by rownum) update_query 
'select updatexml(:var_rec,'||listagg(path_value,',') within group (order by rownum)||')
from dual '
into  update_query
from
(select ''''||xpath||''','|| MY_TRANSFORM(text) path_value
from   
       XMLTable( 
         querystring
         PASSING var_rec AS "doc"
         COLUMNS xpath varchar2(4000) path '/data/@path', 
                 text  varchar2(4000) path '/data/@value'
       )
);
--dbms_output.put_line(update_query);

execute immediate update_query  into v_return using var_rec;


RETURN v_return;
END;

如果你想更新注释值:

 fn_xmlupdate(path,xmltype)

如果要更新属性值

fn_xmlupdate(path,xmltype,@attribute_name)

【讨论】:

    猜你喜欢
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-01
    相关资源
    最近更新 更多