Oracle - XMLTABLE PATH 获取节点祖先
Oracle - XMLTABLE PATH get node ancestor
我有 XML 看起来像:
<root>
<uid>789</uid>
<element>
<uid>123</uid>
<sub>
<text>XYZ</text>
</sub>
</element>
</root>
唯一不变的是 <text>
节点和 <uid>
节点可以升级 2 级的事实。其余节点可以有任何名称,所以我不能使用完全限定的路径。
基于 <text>
节点,我需要找到最近的 <uid>
节点,或者为简单起见,在树中向上 2 层。
我试过了:
WITH cte("XML") AS (
SELECT '<root>
<uid>789</uid>
<element>
<uid>123</uid>
<sub>
<text>XYZ</text>
</sub>
</element>
</root>'
FROM dual
)
SELECT x.*, c.*
FROM cte c,XMLTable('//text'
PASSING XMLTYPE(c."XML")
COLUMNS
text VARCHAR2(4000) PATH '.'
--,guid VARCHAR2(40) PATH '../../uid' -- unsupported XQuery expression
--,guid VARCHAR2(40) PATH 'ancestor::node()[2]/uid'
-- unsupported XQuery expression\
) x
WHERE text IS NOT NULL;
我正在寻找类似于 SQL 服务器的解决方案:
WITH cte("XML") AS (
SELECT CAST('<root>
<uid>789</uid>
<element>
<uid>123</uid>
<sub>
<text>XYZ</text>
</sub>
</element>
</root>' AS XML)
)
SELECT x.value('../../uid[1]', 'VARCHAR(10)') AS uid
,s.x.value('.', 'VARCHAR(10)') AS "text"
FROM cte c
CROSS APPLY c."XML".nodes('//text') s(x)
一个可行的解决方案如下:
SELECT x.*, c.*
FROM cte c,XMLTable('//text/../..'
PASSING XMLTYPE(c."XML")
COLUMNS
text VARCHAR2(4000) PATH 'uid',
guid VARCHAR2(40) PATH 'sub/text'
) x
WHERE text IS NOT NULL;
其结果由两列123
和XYZ
组成。
您应该使用 preceding
- 它会 return 除任何祖先之外的所有节点。
前面集合的顺序是从头到尾。
如果你这样做 preceding::uid
或更一般的 preceding::*
结果将是 (789, 123)。
将所有内容组合在一起:
WITH cte("XML") AS (
SELECT '<root>
<uid>789</uid>
<element>
<uid>123</uid>
<sub>
<text>XYZ</text>
</sub>
</element>
</root>'
FROM dual
)
SELECT x.*, c.*
FROM cte c,XMLTable('//text'
PASSING XMLTYPE(c."XML")
COLUMNS
text VARCHAR2(4000) PATH '.'
,guid VARCHAR2(40) PATH '(preceding::uid)[last() -1]/data(.)' -- 2 -levelup
) x
WHERE text IS NOT NULL;
我有 XML 看起来像:
<root>
<uid>789</uid>
<element>
<uid>123</uid>
<sub>
<text>XYZ</text>
</sub>
</element>
</root>
唯一不变的是 <text>
节点和 <uid>
节点可以升级 2 级的事实。其余节点可以有任何名称,所以我不能使用完全限定的路径。
基于 <text>
节点,我需要找到最近的 <uid>
节点,或者为简单起见,在树中向上 2 层。
我试过了:
WITH cte("XML") AS (
SELECT '<root>
<uid>789</uid>
<element>
<uid>123</uid>
<sub>
<text>XYZ</text>
</sub>
</element>
</root>'
FROM dual
)
SELECT x.*, c.*
FROM cte c,XMLTable('//text'
PASSING XMLTYPE(c."XML")
COLUMNS
text VARCHAR2(4000) PATH '.'
--,guid VARCHAR2(40) PATH '../../uid' -- unsupported XQuery expression
--,guid VARCHAR2(40) PATH 'ancestor::node()[2]/uid'
-- unsupported XQuery expression\
) x
WHERE text IS NOT NULL;
我正在寻找类似于 SQL 服务器的解决方案:
WITH cte("XML") AS (
SELECT CAST('<root>
<uid>789</uid>
<element>
<uid>123</uid>
<sub>
<text>XYZ</text>
</sub>
</element>
</root>' AS XML)
)
SELECT x.value('../../uid[1]', 'VARCHAR(10)') AS uid
,s.x.value('.', 'VARCHAR(10)') AS "text"
FROM cte c
CROSS APPLY c."XML".nodes('//text') s(x)
一个可行的解决方案如下:
SELECT x.*, c.*
FROM cte c,XMLTable('//text/../..'
PASSING XMLTYPE(c."XML")
COLUMNS
text VARCHAR2(4000) PATH 'uid',
guid VARCHAR2(40) PATH 'sub/text'
) x
WHERE text IS NOT NULL;
其结果由两列123
和XYZ
组成。
您应该使用 preceding
- 它会 return 除任何祖先之外的所有节点。
前面集合的顺序是从头到尾。
如果你这样做 preceding::uid
或更一般的 preceding::*
结果将是 (789, 123)。
将所有内容组合在一起:
WITH cte("XML") AS (
SELECT '<root>
<uid>789</uid>
<element>
<uid>123</uid>
<sub>
<text>XYZ</text>
</sub>
</element>
</root>'
FROM dual
)
SELECT x.*, c.*
FROM cte c,XMLTable('//text'
PASSING XMLTYPE(c."XML")
COLUMNS
text VARCHAR2(4000) PATH '.'
,guid VARCHAR2(40) PATH '(preceding::uid)[last() -1]/data(.)' -- 2 -levelup
) x
WHERE text IS NOT NULL;