PL/SQL 中的 XMLPATCH?

XMLPATCH in PL/SQL?

我需要删除 XML 的某些部分(DBMS_METADATA 中的 table 定义)。找到 XMLPATCH 并使其适用于非常小的,例如下面的 XML。但是我面临一大一小两个问题

有谁知道如何优化以下内容以使用最少的内存正确删除 /ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]?

有谁知道如何将下面的代码重写成 PL/SQL 代码?

SELECT XMLPATCH ( XMLTYPE( '<?xml version="1.0"?>
<ROWSET><ROW><TABLE_T><VERS_MAJOR>2</VERS_MAJOR><MAXTRANS>0</MAXTRANS>
<CON1_LIST><CON1_LIST_ITEM><OWNER_NUM>115</OWNER_NUM></CON1_LIST_ITEM></CON1_LIST>
<BHIBOUNDVAL empty="blob"/><PHYPART_NUM>10</PHYPART_NUM></TABLE_T></ROW></ROWSET>')
                , XMLTYPE( '<?xml version="1.0"?>
<xd:xdiff xsi:schemaLocation="http://xmlns.oracle.com/xdb/xdiff.xsd
 http://xmlns.oracle.com/xdb/xdiff.xsd"
 xmlns:xd="http://xmlns.oracle.com/xdb/xdiff.xsd"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <?oracle-xmldiff operations-in-docorder="true" output-model="snapshot" diff-algorithm="global"?>
    <xd:delete-node 
     xd:node-type="element" 
     xd:xpath="/ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]"/>
</xd:xdiff>')
)
FROM DUAL;
```

这个应该可以解决更大的问题,而且速度应该更快:

select
     XMLQuery('copy $i := $p modify
                  delete nodes $i/ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]
               return $i'
               PASSING XMLTYPE( '<?xml version="1.0"?>
                        <ROWSET>
                           <ROW>
                              <TABLE_T>
                                 <VERS_MAJOR>2</VERS_MAJOR>
                                 <MAXTRANS>0</MAXTRANS>
                                 <CON1_LIST>
                                     <CON1_LIST_ITEM>
                                        <OWNER_NUM>115</OWNER_NUM>
                                     </CON1_LIST_ITEM>
                                 </CON1_LIST>
                                 <BHIBOUNDVAL empty="blob"/>
                                 <PHYPART_NUM>10</PHYPART_NUM>
                              </TABLE_T>
                           </ROW>
                        </ROWSET>') AS "p" 
         RETURNING CONTENT
         ) xres
from dual;

不幸的是我们在PL/SQL中仍然使用SQL来更新它:

declare
   x xmltype:= XMLTYPE( '<?xml version="1.0"?>
<ROWSET><ROW><TABLE_T><VERS_MAJOR>2</VERS_MAJOR><MAXTRANS>0</MAXTRANS>
<CON1_LIST><CON1_LIST_ITEM><OWNER_NUM>115</OWNER_NUM></CON1_LIST_ITEM></CON1_LIST>
<BHIBOUNDVAL empty="blob"/><PHYPART_NUM>10</PHYPART_NUM></TABLE_T></ROW></ROWSET>');
   res xmltype;
   g_doc dbms_xmldom.DOMDocument; -- basic DOM-document
   g_node dbms_xmldom.DOMNode;
 
begin
   select
      XMLQuery('copy $i := $p modify
                  delete nodes $i/ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]
               return $i'
               PASSING x AS "p" 
         RETURNING CONTENT
         )
      into res
   from dual;
   dbms_output.put_line(res.getclobval());
end;
/

DELETEXML也是一个答案:

WITH base
AS ( SELECT '<?xml version="1.0"?><ROWSET><ROW>
  <TABLE_T><VERS_MAJOR>2</VERS_MAJOR><MAXTRANS>0</MAXTRANS>
  "<CON1_LIST><CON1_LIST_ITEM><OWNER_NUM>115</OWNER_NUM></CON1_LIST_ITEM></CON1_LIST>"
  <BHIBOUNDVAL empty="blob"/><PHYPART_NUM>10</PHYPART_NUM></TABLE_T></ROW></ROWSET>' xml_data
  FROM dual 
   )
SELECT base.xml_data
     , XMLSERIALIZE( CONTENT DELETEXML(XMLTYPE(base.xml_data), '/ROWSET[1]/ROW[1]/TABLE_T[1]/CON1_LIST[1]') INDENT SIZE=2) xres
FROM base
;

...但它已被弃用,所以 Sayan 的解决方案更好。