在Oracle中使用多个名称空间更新CLOB列

时间:2019-06-11 20:18:57

标签: oracle

我正在尝试更新oracle DB的clob列内的元素。

我面临的第一个挑战是我的clob xml具有2个名称空间,而我无法使其正常工作。

<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
  <esbmsg:Body>
    <Transaction xmlns="http://test.com">
      <test-element>
        <finalElement>false</finalElement>
      </test-elemen>
    </Transaction>
  </esbmsg:Body>
</esbmsg:EsbMessage>



select x.* from cc_messagehistory y
cross join xmltable(
  xmlnamespaces('http://www.test.com/esb/message/1.0' as "esbmsg",
    'http://test.com ' ),
  '/esbmsg:EsbMessage'
  passing xmltype.createxml(y.payload)  
    factext varchar2(10) path '/esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement'
) x;
  

ORA-19102:预期的XQuery字符串文字   19102。00000-“预期的XQuery字符串文字”   *原因:缺少包含XQuery表达式的字符串文字。   *操作:将XQuery表达式指定为字符串文字。错误在行:64列:99

1 个答案:

答案 0 :(得分:0)

ORA-01902的直接原因是您错过了default关键字:

  xmlnamespaces('http://www.test.com/esb/message/1.0' as "esbmsg",
    default 'http://test.com'),

我删除了URI末尾的多余空间,这以后会引起问题。但是您也缺少了columns关键字,并且可以简化CLOB值到XMLType的转换。

将其组合在一起,并与CTE一起提供您的(更正后的)示例XML:

-- CTE for sample data
with cc_messagehistory(payload) as (
select to_clob('<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
  <esbmsg:Body>
    <Transaction xmlns="http://test.com">
      <test-element>
        <finalElement>false</finalElement>
      </test-element>
    </Transaction>
  </esbmsg:Body>
</esbmsg:EsbMessage>') from dual
)
-- actual query
select x.*
from cc_messagehistory y
cross join xmltable (
  xmlnamespaces (
    'http://www.test.com/esb/message/1.0' as "esbmsg",
    default 'http://test.com'
  ),
  '/esbmsg:EsbMessage'
  passing xmltype(y.payload)  
  columns factext varchar2(10)
  path '/esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement'
) x;

FACTEXT   
----------
false

对于更新,您可以执行以下操作:

update cc_messagehistory y
set payload = XMLSerialize(document
  XMLQuery('declare default element namespace "http://test.com"; (: :)
    declare namespace esbmsg="http://www.test.com/esb/message/1.0"; (: :)
    copy $i := $xml modify (
      for $j in $i//esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement
      return replace value of node $j with $new
    )
    return $i'
    passing xmltype(y.payload) as "xml",
    'true' AS "new"
    returning content
  )
  indent size=2
)
where xmlexists('declare default element namespace "http://test.com"; (: :)
  declare namespace esbmsg="http://www.test.com/esb/message/1.0"; (: :)
  $xml//esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement[text()="false"]'
  passing xmltype(y.payload) as "xml");

将源CLOB转换为:

<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
  <esbmsg:Body>
    <Transaction xmlns="http://test.com">
      <test-element>
        <finalElement>true</finalElement>
      </test-element>
    </Transaction>
  </esbmsg:Body>
</esbmsg:EsbMessage>

db<>fiddle(适用于18c;适用于11gR2的错误,但补丁程序级别可能有所不同;也已在12cR1的其他位置成功进行了测试)