Oracle DB更改CLOB中的XML数据库

jgwigjjp  于 2023-10-16  发布在  Oracle
关注(0)|答案(1)|浏览(127)

我为一个具体的问题伤透了脑筋,在那里我什么也找不到。背景:我们将XML配置保存在Oracle数据库的CLOB中。但是,我们将系统切换到新系统。我需要改变所有的<long><int>后的属性“相对”。用于演示:这

<?xml version="1.0" encoding="utf-8"?><!-- SERIALIZER="XSTREAM" --><map>
  <entry>
    <string>CalendarMaintenance</string>
    <map>
      <entry>
        <string>date</string>
        <censored>
          <dbiObjectKey>0</dbiObjectKey>
          <dbiObjectState>C</dbiObjectState>
          <persistentState>0</persistentState>
          <id>date</id>
**          <value>
            <string>Relative</string>
            <long>30</long>
            <long>30</long>
          </value>**
          <sortCriteria>1</sortCriteria>
          <notRequest>false</notRequest>
          <nullRequired>false</nullRequired>
          <satisfiableCondition>true</satisfiableCondition>
        </censored>
      </entry>
    </map>
  </entry>
</map>

需要改成这样

<?xml version="1.0" encoding="utf-8"?><!-- SERIALIZER="XSTREAM" --><map>
  <entry>
    <string>CalendarMaintenance</string>
    <map>
      <entry>
        <string>date</string>
        <censored>
          <dbiObjectKey>0</dbiObjectKey>
          <dbiObjectState>C</dbiObjectState>
          <persistentState>0</persistentState>
          <id>date</id>
**          <value>
            <string>Relative</string>
            <int>30</int>
            <int>30</int>
          </value>**
          <sortCriteria>1</sortCriteria>
          <notRequest>false</notRequest>
          <nullRequired>false</nullRequired>
          <satisfiableCondition>true</satisfiableCondition>
        </censored>
      </entry>
    </map>
  </entry>
</map>

所以简而言之,在Relative Part后面的long标记需要改为int。问题是,它可能是一个标签或两个标签。
有人有什么主意吗?或者有人在Oracle中有Regexp_replace或XML函数的经验?
提前感谢!
我已经尝试了多种解决方案与更新声明。我尝试使用regexp_replace和XML函数,尽管我对这两种方法都不了解。
这只适用于两个长标签:

update table_name 
set column_name = regexp_replace(column_name, '<value>(\s+)<string>Relative</string>(\s+)<long>([0-9a-zA-Z]+)</long>(\s+)<long>([0-9a-zA-Z]+)</long>', '<value>\1<string>Relative</string>\2<int>\3</int>\4<int>\5</int>')
where regexp_like(column_name, '<long>([0-9]+)</long>');

这个函数使用一个XML函数,但不返回整个输入XML(如上所示)

update table_name
    set column_name = regexp_replace(
        EXTRACT(XMLTYPE.createXML(column_name), '//value[string="Relative"]/long'),
        '<long>([0-9a-zA-Z]+)</long>',
        '<int>\1</int>')
    where
        regexp_like(column_name, '<long>([0-9]+)</long>');

输出是这样的:

<int>30</int><int>30</int>
2vuwiymt

2vuwiymt1#

NEVER使用字符串函数解析XML;始终使用适当的XML解析器。

您可以使用FLOWR表达式重写XML:

UPDATE table_name
SET xml = XMLSERIALIZE(
            CONTENT XMLQUERY(
              'copy $e := .
              modify (
              for $i in $e/map/entry/map/entry/censored/value[string="Relative"]/long
                return rename node $i as "int"
              )
              return $e'
              PASSING XMLTYPE(xml) RETURNING CONTENT
            ) AS CLOB
          );

其中,对于样本数据:

CREATE TABLE table_name (xml) AS
SELECT EMPTY_CLOB() || '<?xml version="1.0" encoding="utf-8"?><!-- SERIALIZER="XSTREAM" --><map>
  <entry>
    <string>CalendarMaintenance</string>
    <map>
      <entry>
        <string>date</string>
        <censored>
          <dbiObjectKey>0</dbiObjectKey>
          <dbiObjectState>C</dbiObjectState>
          <persistentState>0</persistentState>
          <id>date</id>
          <value>
            <string>Relative</string>
            <long>30</long>
            <long>30</long>
          </value>
          <sortCriteria>1</sortCriteria>
          <notRequest>false</notRequest>
          <nullRequired>false</nullRequired>
          <satisfiableCondition>true</satisfiableCondition>
        </censored>
      </entry>
    </map>
  </entry>
</map>' FROM DUAL;

然后,表格将包含:
| XML|
| --|
| 日历维护日期0C0日期相对30301假假真|
如果你想替换任何value标签的子标签(而不是在特定路径上),那么用$e//value[string="Relative"]/long替换XPATH $e/map/entry/map/entry/censored/value[string="Relative"]/long
fiddle
如果你只想更新string元素之后的兄弟元素,那么你可以使用XPATH $e//value/string[text()="Relative"]/following-sibling::long
fiddle

相关问题