从 XML 到 Oracle 12c 中的路径列表

From XML to list of paths in Oracle 12c

From XML to list of paths in Oracle PL/SQL environment 展示了如何列出 XML 文档中每个 XML 元素的所有 XPATH 及其对应的值。我的问题是如何列出 XML 元素的所有 XPATH 它们属性的 XPATH 以及相应的值?

Oracle 设置:

CREATE TABLE xml_data ( xml ) AS
  SELECT XMLTYPE('
    <ALFA>
      <BETA>0123</BETA> 
      <GAMMA attribute1="value1">2345</GAMMA> 
      <DELTA attribute2="value2"> 
         <EPSILON attribute3="value3" attribute4="value4">3</EPSILON> 
      </DELTA> 
    </ALFA> 
  ')
  FROM DUAL;

预期输出

| ELEMENT_PATH                   | ELEMENT_TEXT |
|--------------------------------|--------------|
| ALFA                           | (null)       |
| ALFA/BETA                      | 0123         |
| ALFA/GAMMA                     | 2345         |
| ALFA/GAMMA/@attribute1         | value1       |
| ALFA/DELTA                     | (null)       |
| ALFA/DELTA/@attribute2         | value2       |
| ALFA/DELTA/EPSILON             | 3            |
| ALFA/DELTA/EPSILON/@attribute3 | value3       |
| ALFA/DELTA/EPSILON/@attribute4 | value4       | 

SQL Fiddle

Oracle 11g R2 架构设置:

CREATE TABLE xml_data ( xml ) AS
  SELECT XMLTYPE('
    <ALFA>
      <BETA>0123</BETA> 
      <GAMMA attribute1="value1">2345</GAMMA> 
      <DELTA attribute2="value2"> 
         <EPSILON attribute3="value3" attribute4="value4">3</EPSILON> 
      </DELTA> 
    </ALFA> 
  ')
  FROM DUAL;   

查询 1:

select xpath, text
from   xml_data d
       CROSS JOIN
       XMLTable( 
         'for $i in $doc/descendant-or-self::*
            let $path := $i/string-join(ancestor-or-self::*/name(.), ''/'')
            return <data>{attribute path {$path}, attribute value {$i/text()}}</data>' 
         PASSING d.xml AS "doc"
         COLUMNS xpath varchar2(4000) path '/data/@path', 
                 text  varchar2(4000) path '/data/@value'
       )
UNION ALL
select xpath, text
from   xml_data d
       CROSS JOIN
       XMLTable( 
         'for $i in $doc/descendant-or-self::*
            let $path := $i/string-join(ancestor-or-self::*/name(.), ''/'')
            for $j in $i/attribute::*
              return <data>{attribute path { concat( $path, "/@", $j/name(.) ) }, attribute value {$j}}</data>' 
         PASSING d.xml AS "doc"
         COLUMNS xpath varchar2(4000) path '/data/@path', 
                 text  varchar2(4000) path '/data/@value'
       )

Results:

|                          XPATH |   TEXT |
|--------------------------------|--------|
|                           ALFA | (null) |
|                      ALFA/BETA |   0123 |
|                     ALFA/GAMMA |   2345 |
|                     ALFA/DELTA | (null) |
|             ALFA/DELTA/EPSILON |      3 |
|         ALFA/GAMMA/@attribute1 | value1 |
|         ALFA/DELTA/@attribute2 | value2 |
| ALFA/DELTA/EPSILON/@attribute3 | value3 |
| ALFA/DELTA/EPSILON/@attribute4 | value4 |