修改XML节点值 - 与Oracle 12c等效的UpdateXML

时间:2014-01-09 09:23:14

标签: sql xml oracle xquery oracle12c

我有一些示例代码如下:

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;

我的要求是,当/node_root/node_1列中的x不为空时,请将/node_root/node_2/node_root/node_3/node_root/node_4的值替换为null。我在Updatexml查询中使用的SELECT函数也是如此。

这里的问题是Updatexml在Oracle 12c中不起作用。这就是我在子查询中使用Xmltable的原因,它在过滤数据方面非常有效,但是我无法用null替换节点值。

我尝试查看Oracle Docs的XQuery,但无法理解它如何有助于替换节点值。

请提供一个描述性的例子。

1 个答案:

答案 0 :(得分:2)

Oracle文档recommends to use XQuery to update XML。所以首先要尝试。

首先,有可能采用旧方法和功能。可以使用下面的XQuery代替调用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  

另一种更短更直观的变体:

    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

此外,只有在条件不匹配时才可以返回修改后的XML值:

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

因此,有许多变体可以对XML值执行操作,但这需要更深入的XQueryXPath知识,而不是相对简单的XmlUpdate函数......

相关问题