Oracle SQL UPDATEXML替换节点值,即使它为空

时间:2018-07-12 15:46:07

标签: sql xml oracle xpath updatexml

我有一个包含大量XML的CLOB数据库列:XML_CONF 我通常使用updateXML函数来修改XML的特定节点,效果很好。但是今天,我遇到了很多麻烦,因为我要修改的节点有时是空的,并且在这种情况下不起作用...

具有空textValue的XML示例:

<ns2:ConfigurationTree xmlns:ns2="com.xxxx" xmlns="com.xxxx.yyyy">
<ns2:ConfigurableProduct ...>...
    <ns2:CPNode name="cpX">...
        <ns2:FormProperty name="fpX">
            <ns2:SingleValuation isCommentUserChoice="false" isValueUserChoice="false" isQtyUserChoice="false">
                <ns2:Value>
                    **<ns2:textValue/>**
                </ns2:Value>
            </ns2:SingleValuation>
        </ns2:FormProperty>
    </ns2:CPNode>
</ns2:ConfigurableProduct>

带有textValue的XML示例:

<ns2:ConfigurationTree xmlns:ns2="com.xxxx" xmlns="com.xxxx.yyyy">
<ns2:ConfigurableProduct ...>...
    <ns2:CPNode name="cpX">...
        <ns2:FormProperty name="fpX">
            <ns2:SingleValuation isCommentUserChoice="false" isValueUserChoice="false" isQtyUserChoice="false">
                <ns2:Value>
                    **<ns2:textValue>123456</ns2:textValue>**
                </ns2:Value>
            </ns2:SingleValuation>
        </ns2:FormProperty>
    </ns2:CPNode>
</ns2:ConfigurableProduct>

例如,要将textValue内容替换为“ 78910”,我尝试使用此方法来处理两种情况:

update T_TABLE set XML_CONF = updatexml(xmltype(XML_CONF),
'//FormProperty[@name="fpX"]//Value/textValue',xmltype('<textValue>78910</textValue>'),
'//FormProperty[@name="fpX"]//Value/textValue/text()','78910',
'xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy"').getClobVal();

但是结果破坏了XML(节点中没有更多的前缀和xmlns空):

<ns2:ConfigurationTree xmlns:ns2="com.xxxx" xmlns="com.xxxx.yyyy">
<ns2:ConfigurableProduct ...>...
    <ns2:CPNode name="cpX">...
        <ns2:FormProperty name="fpX">
            <ns2:SingleValuation isCommentUserChoice="false" isValueUserChoice="false" isQtyUserChoice="false">
                <ns2:Value>
                    **<textValue xmlns="">78910</textValue>**
                </ns2:Value>
            </ns2:SingleValuation>
        </ns2:FormProperty>
    </ns2:CPNode>
</ns2:ConfigurableProduct>

如果我回想起具有不同textValue的相同请求,此后它将不再更新...我认为这是因为前缀在节点上已损坏...

我尝试使用XMLQuery(Oracle 12)来做到这一点,但这是同样的问题。

编辑

它几乎可以与:

    update T_TABLE set XML_CONF = updatexml(xmltype(XML_CONF),
  '//FormProperty[@name="fpX"]//Value/textValue/text()','78910',
  '//FormProperty[@name="fpX"]//Value/textValue[not(text())]',xmltype('<textValue>78910</textValue>'),
  xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy"' ).getClobVal();

但是在输出中,我没有新的ns2:textValue节点,只有:

<ns2:Value><textValue xmlns="">78910</textValue></ns2:Value>

为什么它会中断ns2前缀,为什么还要放置一个空的xmlns属性?

如果我在新节点中指定名称空间,则可以使用该名称空间,但它似乎无用,因为它们已在根节点中声明:

    update T_TABLE set XML_CONF = updatexml(xmltype(XML_CONF),
  '//FormProperty[@name="fpX"]//Value/textValue/text()','78910',
  '//FormProperty[@name="fpX"]//Value/textValue[not(text())]',xmltype('<ns2:textValue xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy">78910</ns2:textValue>'),
  'xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy"' ).getClobVal();

给予:

<ns2:textValue xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy">78910</ns2:textValue></ns2:Value>

1 个答案:

答案 0 :(得分:1)

您可以这样做:

update T_TABLE set XML_CONF = updatexml(xmltype(XML_CONF),
  '//ns2:FormProperty[@name="fpX"]//ns2:Value/ns2:textValue/text()','78910',
  '//ns2:FormProperty[@name="fpX"]//ns2:Value/ns2:textValue[not(text())]',
     xmlelement("ns2:textValue", xmlattributes('com.xxxx' as "xmlns:ns2"), '78910'),
  'xmlns:ns2="com.xxxx" xmlns="com.xxxx.yyyy"').getClobVal();

标识文本节点或无文本的节点;或ns2与默认值相同(来自注释):

update T_TABLE set XML_CONF = updatexml(xmltype(XML_CONF),
  '//FormProperty[@name="fpX"]//Value/textValue/text()','78910',
  '//FormProperty[@name="fpX"]//Value/textValue[not(text())]',
     xmlelement("ns2:textValue", xmlattributes('com.xxxx' as "xmlns:ns2"), '78910'),
  'xmlns:ns2="com.xxxx" xmlns="com.xxxx"').getClobVal();

db<>fiddle和您的真实名称空间。新创建的textValue节点重新声明了ns2,但在功能上没关系。

当然,在12c中不推荐使用updateXML,但是您应该能够对Xquery update执行相同的操作。实际上,这更简单:

update t_table set xml_conf = xmlquery(
   'copy $d := .
    modify (
      for $i in $d//*:FormProperty[@name="fpX"]//*:Value/*:textValue
        return replace value of node $i with $newValue
    )
    return $d'
    passing xmltype(xml_conf), '78910' as "newValue"
    returning content
  ).getClobVal();

为了简化起见,我对名称空间进行了通配(实际上,即使ns2与默认名称不同,我也没有弄清楚如何使其与名称空间前缀一起使用)。由于某种原因,db <> fiddle和SQL Fiddle均出现“ ORA-19112:评估期间引发错误:XQuery Update无法编译”,两者均为11.20.02;但可以在我的11.2.0.4和12.2.0.1数据库上正常工作。

您可以添加对现有相关节点的检查,以避免不必要的更新。

相关问题