Modify XML node value- UpdateXML equivalent for Oracle 12c

China☆狼群 提交于 2019-12-23 18:36:13

问题


I have some sample code as follows:

WITH xtbl AS
         (SELECT 1 AS xtbl_id,
                 xmltype ('<node_root>
                        <node_1>12</node_1>
                        <node_2>233</node_2>
                        <node_3>223</node_3>
                        <node_4>234</node_4>
                   </node_root>') AS x
            FROM Dual
          UNION ALL
          SELECT 2, xmltype ('<node_root>
                        <node_1></node_1>
                        <node_2>233</node_2>
                        <node_3>223</node_3>
                        <node_4>234</node_4>
                   </node_root>')
            FROM Dual)
SELECT xtbl_id,
       x,
       Updatexml (x,
                  '/node_root/node_2',
                  NULL,
                  '/node_root/node_3',
                  NULL,
                  '/node_root/node_4',
                  NULL)
           AS xcol
  FROM xtbl
 WHERE (SELECT node_1
          FROM Xmltable ('node_root'
                         PASSING x
                         COLUMNS node_1 INTEGER PATH 'node_1'))
           IS NOT NULL;

My requirement is that whenever /node_root/node_1 in column x is not null then replace the values for /node_root/node_2, /node_root/node_3 and /node_root/node_4 to null. The Updatexml function I have used in my SELECT query does the same.

The problem here is that Updatexml doesn't work in Oracle 12c. This is why I have used Xmltable in the subquery and it works perfect at filtering the data, but I am not able to replace the node values with null.

I tried looking at Oracle Docs for XQuery but couldn't understand how it can be helpful at replacing node values.

Kindly provide a descriptive example.


回答1:


Oracle documentation recommends to use XQuery to update XML. So it's first thing to try.

First, it's possible with old approach with function. XQuery below may be used instead of call to XmlUpdate:

    XMLQuery(
      ' 
        declare function local:copy-replace($element as element()) {  
          if ($element/self::node_2) then <node_2/>
          else if ($element/self::node_3) then <node_3/>
          else if ($element/self::node_4) then <node_4/>
          else element {node-name($element)}  
                       {$element/@*, 
                        for $child in $element/node()  
                        return if ($child instance of element())  
                               then local:copy-replace($child)  
                               else $child  
                       }  
        };  
        local:copy-replace($p/*)
      '
      passing x as "p" returning content
    ) as xcol_2  

Another, shorter and more intuitive variant:

    XMLQuery(
      '              
        copy $p2 := $p
        modify(
          replace value of node $p2/node_root/node_2 with "",
          replace value of node $p2/node_root/node_3 with "",
          replace value of node $p2/node_root/node_4 with ""
        )
        return $p2
      '
      passing x as "p" returning content
    ) as xcol_3

And in addition, it's possible to return a modified XML value only if condition not matched:

WITH xtbl AS
     (SELECT 1 AS xtbl_id,
             xmltype ('<node_root>
                    <node_1>12</node_1>
                    <node_2>233</node_2>
                    <node_3>223</node_3>
                    <node_4>234</node_4>
               </node_root>') AS x
        FROM Dual
      UNION ALL
      SELECT 2, xmltype ('<node_root>
                    <node_1></node_1>
                    <node_2>233</node_2>
                    <node_3>223</node_3>
                    <node_4>234</node_4>
               </node_root>')
        FROM Dual)
SELECT xtbl_id,
   x,
    XMLQuery(
      '   
        for $test in $p/*
        return 
          if( empty($p/node_root/node_1/text()) )             
            then $p
            else (
             copy $p2 := $p
              modify(
                replace value of node $p2/node_root/node_2 with "",
                replace value of node $p2/node_root/node_3 with "",
                replace value of node $p2/node_root/node_4 with ""
              )
              return $p2
           )   
      '
      passing x as "p" returning content
    ) as xcol_4
FROM xtbl

So there are many variants to perform operations on XML values, but this requires deeper knowledge of XQuery and XPath than a relatively simple XmlUpdate function ...



来源:https://stackoverflow.com/questions/21016083/modify-xml-node-value-updatexml-equivalent-for-oracle-12c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!