Oracle - XMLTABLE PATH получить предок узла - PullRequest
0 голосов
/ 11 марта 2019

У меня есть 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 Server:

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)

db <> Fiddle demo

Ответы [ 2 ]

1 голос
/ 11 марта 2019

Вы должны использовать preceding - он вернет все узлы, кроме любого предка.
Порядок предыдущей коллекции от начала до конца. Если вы сделаете это 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;
1 голос
/ 11 марта 2019

Один рабочий раствор выглядит следующим образом:

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.

...