Oracle SQL UPDATEXML替换节点值,即使它为';它是空的

Oracle SQL UPDATEXML替换节点值,即使它为';它是空的,sql,xml,oracle,xpath,updatexml,Sql,Xml,Oracle,Xpath,Updatexml,我有一个CLOB数据库列,其中包含一个大XML:XML\u CONF 我通常使用函数updateXML来修改XML的特定节点,它非常有用。但今天,我有很多麻烦,因为我想修改的节点有时是空的,在这种情况下它不工作 文本值为空的XML示例: <ns2:ConfigurationTree xmlns:ns2="com.xxxx" xmlns="com.xxxx.yyyy"> <ns2:ConfigurableProduct ...>... <ns2:CPNode

我有一个CLOB数据库列,其中包含一个大XML:XML\u CONF 我通常使用函数updateXML来修改XML的特定节点,它非常有用。但今天,我有很多麻烦,因为我想修改的节点有时是空的,在这种情况下它不工作

文本值为空的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>
<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的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>
<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>

...
...
**123456**

例如,为了将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();
update T_TABLE set XML_CONF=updatexml(xmltype(XML_CONF),
'//FormProperty[@name=“fpX”]///Value/textValue',xmltype('78910'),
“//FormProperty[@name=“fpX”]//Value/textValue/text()”,“78910”,
'xmlns:ns2=“com.xxxx”xmlns=“xxxx.yyyy”).getClobVal();
但结果破坏了XML(不再有前缀,节点中的xmlns为空):


...
...
**78910**

如果我回忆起同一个请求,使用不同的textValue,它不会再更新任何内容。。。我想这是因为前缀在节点上被破坏了

我尝试用XMLQuery(Oracle12)实现这一点,但问题是一样的

编辑

它几乎适用于:

    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();
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('78910'),
xmlns:ns2=“com.xxxx”xmlns=“xxxx.yyyy”).getClobVal();
但在输出中,我没有新的ns2:textValue节点,我只有:

<ns2:Value><textValue xmlns="">78910</textValue></ns2:Value>
78910
为什么它会破坏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();
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('78910'),
'xmlns:ns2=“com.xxxx”xmlns=“xxxx.yyyy”).getClobVal();
给出:

<ns2:textValue xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy">78910</ns2:textValue></ns2:Value>
78910
您可以执行以下操作:

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
与默认值相同(来自注释):

使用真实的名称空间。新创建的
textValue
节点重新声明了
ns2
,但在功能上这并不重要

当然,updateXML在12c中是不推荐使用的,但是您应该能够用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
与默认值不同)。由于某种原因,在dbfiddle和sqlfiddle上都得到了“ORA-19112:评估期间引发的错误:无法编译XQuery更新”,这两个版本都是11.20.02;但在我的11.2.0.4和12.2.0.1数据库上运行良好


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

奇怪,它不起作用:/在两个请求之后,XML仍然为空:fpcodeActiveArty它在处理示例时起作用。我不知道您在做什么不同的事情,我看不到原始XML或您正在做的实际更新。也许您的
ns2
定义不太匹配,或者其他什么东西,这些东西在静默中不会起任何作用。但这显然只是一个猜测。我在这里修改了fiddle以放置整个XML,但字符串太长:我无法修改的formProperty的名称是:name=“fpcodeActiveArty”此外,我只是看到,即使您的解决方案有效,在空textValue节点的情况下,它也不会保留XXX,而是直接将值“78910”放入就像78910一样。事实上,如果我只是将名称空间的真正声明放在您的小提琴中,它就不再起作用了: