如何解决我可以在Xquery中使用用户定义的函数替换PLSQL中的节点值吗?
我想通过我的函数 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.
我可以在“用my_calculator($ l3)返回节点$ l3的替换值”中使用用户函数吗? 非常感谢。
解决方法
您不能在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>
,
因为我不能在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)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。