我的表中有一个 CLOB 列,其中填充了 XML 数据。 该预定义字符串可能是每行多个节点的值。 目的只是获得一份受影响的 XML 节点的报告。
比如说,这是行 ID 10,带有 CLOB_XML
<personInfo>
<name>Blank</name>
<addressGroup>
<town>Cape</town>
<city>Blank</city>
</addressGroup>
</personInfo>
我怎样才能像这样返回:
行ID | CLOB_XML |
---|---|
10 |
|
10 |
|
尝试过 INSTR - 似乎无法捕获多次出现的情况。 EVALSTRING 仅获取值 - 我需要搜索提供值的节点
如果您想要仅包含匹配节点的 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;
您可以从 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'
;
并且 - 不太清楚您到底期望什么 - 在结果中添加您想要的格式。
如果您只想要具有该值的节点,您可以在 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 |
(这不会保留属性,但您还没有显示任何属性,如果您有任何属性,也可能不会保留它们。)