如何根据条件从 Oracle XMLTYPE 中删除节点?

How to delete a node from Oracle XMLTYPE based on a condition?

我有一个 XML 数据存储在 CLOB 列中,我想根据特定条件删除一些节点。

示例XML数据:

<?xml version="1.0" encoding="UTF-8"?>
<payment>
  <person>
    <surname>Marco</surname>
    <name>Gralike</name>
    <salary>2345</salary>
  </person>
  <person>
    <surname>ABC</surname>
    <name>TEST</name>
    <salary>1234</salary>
    <person>
    <surname>Tiger</surname>
    <name>Scott</name>
    <salary>2222</salary>
  </person>
  </person>
 </payment>
 <payment>
  <person>
    <surname>BertJan</surname>
    <name>Meinders</name>
    <salary>3456</salary>
    <salary>125</salary>
  </person>
  <person>
    <surname>XYZ</surname>
    <name>TEST</name>
    <salary>1234</salary>
  </person>
 </payment>
 <payment>
  <person>
    <surname>Chris</surname>
    <name>Gralike</name>
    <salary>4567</salary>
  </person>
  <person>
    <surname>LMN</surname>
    <name>TEST</name>
    <salary>1234</salary>
  </person>
 </payment>

我需要一个 Oracle PLSQL 脚本来删除所有包含 TEST 的人员标签。

最终输出为:

<?xml version="1.0" encoding="UTF-8"?>
<payment>
  <person>
    <surname>Marco</surname>
    <name>Gralike</name>
    <salary>2345</salary>
  </person>
 </payment>
 <payment>
  <person>
    <surname>BertJan</surname>
    <name>Meinders</name>
    <salary>3456</salary>
    <salary>125</salary>
  </person>
 </payment>
 <payment>
  <person>
    <surname>Chris</surname>
    <name>Gralike</name>
    <salary>4567</salary>
  </person>
 </payment>

提前致谢。

您提供的 XML 没有根,XML 解析器无法解析。

假设它确实如此(比如 payments),如下所示:

create table t(txt clob);
insert into t values('<?xml version="1.0" encoding="UTF-8"?>
<payments>
    <payment>
        <person>
            <surname>Marco</surname>
            <name>Gralike</name>
            <salary>2345</salary>
        </person>
        <person>
            <surname>ABC</surname>
            <name>TEST</name>
            <salary>1234</salary>
            <person>
                <surname>Tiger</surname>
                <name>Scott</name>
                <salary>2222</salary>
            </person>
        </person>
    </payment>
    <payment>
        <person>
            <surname>BertJan</surname>
            <name>Meinders</name>
            <salary>3456</salary>
            <salary>125</salary>
        </person>
        <person>
            <surname>XYZ</surname>
            <name>TEST</name>
            <salary>1234</salary>
        </person>
    </payment>
    <payment>
        <person>
            <surname>Chris</surname>
            <name>Gralike</name>
            <salary>4567</salary>
        </person>
        <person>
            <surname>LMN</surname>
            <name>TEST</name>
            <salary>1234</salary>
        </person>
    </payment>
</payments>');

你可以使用这个:

update t
set txt = to_clob(deletexml(
  xmltype(t.txt),
  '//payment/person[./name[text()="TEST"]]'
));

生产:

<?xml version="1.0" encoding="UTF-8"?>
<payments>
    <payment>
        <person>
            <surname>Marco</surname>
            <name>Gralike</name>
            <salary>2345</salary>
        </person>
    </payment>
    <payment>
        <person>
            <surname>BertJan</surname>
            <name>Meinders</name>
            <salary>3456</salary>
            <salary>125</salary>
        </person>
    </payment>
    <payment>
        <person>
            <surname>Chris</surname>
            <name>Gralike</name>
            <salary>4567</salary>
        </person>
    </payment>
</payments>

编辑:

如果要删除没有给定子节点的节点,请使用:

update t
set txt = to_clob(deletexml(
  xmltype(t.txt),
  '//payment[not(./person)]'
));

它将删除所有没有人的付款标签。

deleteXML() 已被弃用。如果可能,您应该使用 XQuery 更新。如果完整路径是固定的,也尽量避免使用“//”。

with XML_TABLE as 
(
   select XMLTYPE('<?xml version="1.0" encoding="UTF-8"?>
<payments>
<payment>
    <person>
        <surname>Marco</surname>
        <name>Gralike</name>
        <salary>2345</salary>
    </person>
    <person>
        <surname>ABC</surname>
        <name>TEST</name>
        <salary>1234</salary>
        <person>
            <surname>Tiger</surname>
            <name>Scott</name>
            <salary>2222</salary>
        </person>
    </person>
</payment>
<payment>
    <person>
        <surname>BertJan</surname>
        <name>Meinders</name>
        <salary>3456</salary>
        <salary>125</salary>
    </person>
    <person>
        <surname>XYZ</surname>
        <name>TEST</name>
        <salary>1234</salary>
    </person>
</payment>
<payment>
    <person>
        <surname>Chris</surname>
        <name>Gralike</name>
        <salary>4567</salary>
    </person>
    <person>
        <surname>LMN</surname>
        <name>TEST</name>
        <salary>1234</salary>
    </person>
</payment>
</payments>') as XML_COLUMN from dual
)
SELECT XMLQuery(
    'copy $NEWXML := $XML modify (
      delete nodes $NEWXML/payments/payment/person[name[text()=$NAME]]
     )
     return $NEWXML'
     passing XML_COLUMN as "XML",
             'TEST' as "NAME"
     returning CONTENT
   )
from XML_TABLE
/

您可以尝试使用 SQL Workbench 在 livesql.oracle.com

截取此代码

这个有效

with XML_TABLE as
(
   select XMLTYPE('<?xml version="1.0" encoding="UTF-8"?>
<payments>
  <payment>
    <person>
     <surname>XYZ</surname>
  <name>TEST</name>
  <salary>1234</salary>
</person>
<id>person 4</id>
 </payment>
 <payment>
<id>person 5</id>
</payment>
 </payments>') as XML_COLUMN from dual
)
SELECT XMLQuery(
'copy $NEWXML := $XML modify (
  delete nodes $NEWXML/payments/payment[not(person)]
 )
 return $NEWXML'
 passing XML_COLUMN as "XML",
         'TEST' as "NAME"
 returning CONTENT
)
from XML_TABLE

<?xml version="1.0" encoding="WINDOWS-1252"?>
<payments>
  <payment>
 <person>
  <surname>XYZ</surname>
  <name>TEST</name>
  <salary>1234</salary>
</person>
  <id>person 4</id>
 </payment>
</payments>

SQL>