使用每行定义值的所有出现位置返回 XML 节点名称

问题描述 投票:0回答:3

我的表中有一个 CLOB 列,其中填充了 XML 数据。 该预定义字符串可能是每行多个节点的值。 目的只是获得一份受影响的 XML 节点的报告。

比如说,这是行 ID 10,带有 CLOB_XML

<personInfo>
<name>Blank</name>
<addressGroup>
<town>Cape</town>
<city>Blank</city>
</addressGroup>
</personInfo>

我怎样才能像这样返回:

行ID CLOB_XML
10
<personInfo><name>Blank</name></personInfo>
10
<addressGroup><city>Blank</city></addressGroup>

尝试过 INSTR - 似乎无法捕获多次出现的情况。 EVALSTRING 仅获取值 - 我需要搜索提供值的节点

sql oracle clob
3个回答
1
投票

如果您想要仅包含匹配节点的 XML,则可以使用 FLWOR 表达式来删除不匹配的叶节点:

SELECT t.id, x.*
FROM   table_name t
       CROSS JOIN XMLTABLE(
         'copy $j := /.
          modify
          (
            for $i in $j//*/.[not(text()="Blank" or *)]
               return delete node $i
          )
          return $j
         '
         PASSING XMLTYPE(t.value)
         COLUMNS 
            xml XMLTYPE PATH '/.'
       ) x;

对于样本数据:

CREATE TABLE table_name (id, value) AS
SELECT 10, EMPTY_CLOB() || '<personInfo>
<name>Blank</name>
<addressGroup>
<town>Cape</town>
<city>Blank</city>
</addressGroup>
</personInfo>' FROM DUAL;

输出:

身份证 XML
10 空白空白

如果您想要父元素并删除不匹配的子节点,则:

SELECT t.id, x.xml
FROM   table_name t
       CROSS JOIN XMLTABLE(
         '//*[text()="Blank"]/..'
         PASSING XMLTYPE(t.value)
         COLUMNS 
            xml XMLTYPE PATH 'copy $j := .
              modify
              (
                for $i in $j//*/*/.[not(text()="Blank") or *]
                  return delete node $i
              )
              return $j'
       ) x;

哪个输出:

身份证 XML
10 空白
10 空白

或者,修改 Alex Poole 的解决方案:

SELECT t.id,
       XMLELEMENT(EVALNAME x.parent, x.xml).getClobVal() AS xml
FROM   table_name t
       CROSS JOIN XMLTABLE(
         '//*[text()="Blank"]'
         PASSING XMLTYPE(t.value)
         COLUMNS 
            xml    XMLTYPE       PATH '.',
            parent VARCHAR2(200) PATH './../name()'
       ) x;

小提琴


0
投票

您可以从 XMLTABLE 查询开始:

with data(id, xml) as (
    select 1, xmltype(q'~<root><name>Blank</name>
<addressGroup>
<town>Cape</town>
<city>Blank</city>
</addressGroup></root>~')
)
select id, gparent, parent, name from 
data d, xmltable('//*/.'
        passing d.xml
        columns 
            gparent varchar2(64) path '../../name()',
            parent varchar2(64) path '../name()',
            name varchar2(64) path 'name()',
            content varchar2(4000) path 'text()'
    ) t1
where content = 'Blank'
;

并且 - 不太清楚您到底期望什么 - 在结果中添加您想要的格式。


0
投票

如果您只想要具有该值的节点,您可以在 XMLTable 调用中使用过滤通配符 XPath 来获取它们:

select t.id, x.node
from your_table t
cross join xmltable('//*[text()="Blank"]'
  passing xmltype(t.clob_xml)
  columns
    node xmltype path '.'
) x
身份证 节点
10 空白
10 空白

但是你也想要父节点。如果您只想要节点名称,您也可以直接这样做:

select t.id, x.parent_name, x.name, x.text
from your_table t
cross join xmltable('//*[text()="Blank"]'
  passing xmltype(t.clob_xml)
  columns
    parent_name varchar2(4000) path '../name()',
    name varchar2(4000) path 'name()',
    text varchar2(4000) path 'text()'
) x
身份证 PARENT_NAME 姓名 文字
10 人员信息 名字 空白
10 地址组 城市 空白

但是您想要节点结构 - 并且没有其他兄弟/子节点。因此您可以从该数据重新创建节点:

select t.id,
  xmlelement(evalname x.parent_name,
    xmlelement(evalname x.name, x.text)).getclobval() as clob_xml
from your_table t
cross join xmltable('//*[text()="Blank"]'
  passing xmltype(t.clob_xml)
  columns
    parent_name varchar2(4000) path '../name()',
    name varchar2(4000) path 'name()',
    text varchar2(4000) path 'text()'
) x
身份证 CLOB_XML
10 空白
10 空白

小提琴

(这不会保留属性,但您还没有显示任何属性,如果您有任何属性,也可能不会保留它们。)

© www.soinside.com 2019 - 2024. All rights reserved.