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

时间:2017-01-07 07:55:29

标签: sql xml oracle xmltype

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

示例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>

如果包含TEST,我需要一个Oracle PLSQL脚本来删除所有人物标签。

最终输出将是:

<?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>

提前致谢。

4 个答案:

答案 0 :(得分:1)

您提供的XML没有root,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)]'
));

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

答案 1 :(得分:0)

deleteXML()已被弃用。如果可能,您应该使用XQuery更新。同时尽量避免使用&#39; //&#39;如果完整路径是固定的。

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
/

您可以在livesql.oracle.com上使用SQL Workbench尝试使用此代码剪切

答案 2 :(得分:0)

感谢您的样品。

<payment> 
<person>
 <surname>XYZ</surname> 
 <name>TEST</name> 
 <salary>1234</salary> 
 </person> 
<id>person 4</id> 
</payment> 

如果其中一个节点包含上述数据,那么在使用deletexml后我得到:

<payment> 
<id>person 4</id> 
</payment> 

如果此节点不包含任何<person>标记,如何删除该节点?

即如何删除以下节点,因为它不包含<person>标记:

   <payment> 
    <id>person 4</id> 
    </payment>

答案 3 :(得分:0)

这有效

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&GT;