Вы можете использовать цепочечные вызовы XMLTable:
select x1.type, x1.ring_num, x2.parent, x2.coordinates
from xmltable(
xmlnamespaces(default 'http://www.opengis.net/gml/'),
'/Polygon/*'
passing p_xml
columns type varchar2(8) path './local-name()',
ring_num for ordinality,
nodes xmltype path '//posList/..'
) x1
cross join xmltable (
xmlnamespaces(default 'http://www.opengis.net/gml/'),
'/*'
passing x1.nodes
columns parent varchar2(21) path './name()',
coordinates varchar2(30) path 'posList'
) x2;
(конечно, корректируя типы и размеры выходных данных в соответствии с вашими реальными данными)
Таблица x1 получает внешний / внутренний вид узлов, добавляет порядковый столбец для «номера кольца» и включает в себя столбец XMLType, который имеет все узлы, являющиеся родителями узла posList
. Затем он передается в x2, который извлекает несколько posList
координат и родителей.
Демонстрация с использованием CTE для предоставления документа XML вместо PL / SQL:
with t (p_xml) as (
select xmltype('<gml:Polygon xmlns:gml="http://www.opengis.net/gml/">
<gml:exterior>
<gml:LinearRing>
<gml:posList > [coordinates] </gml:posList>
</gml:LinearRing>
</gml:exterior>
<gml:interior>
<gml:Ring>
<gml:curveMember>
<gml:Curve>
<gml:segments>
<gml:LineStringSegment>
<gml:posList > [coordinates] </gml:posList>
</gml:LineStringSegment>
<gml:Arc>
<gml:posList > [coordinates] </gml:posList>
</gml:Arc>
<gml:LineStringSegment>
<gml:posList > ... </gml:posList>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
</gml:curveMember>
</gml:Ring>
</gml:interior>
<gml:interior>
<gml:LinearRing>
<gml:posList > [coordinates] </gml:posList>
</gml:LinearRing>
</gml:interior>
</gml:Polygon>') from dual
)
select x1.type, x1.ring_num, x2.parent, x2.coordinates
from t
cross join xmltable(
xmlnamespaces(default 'http://www.opengis.net/gml/'),
'/Polygon/*'
passing t.p_xml
columns type varchar2(8) path './local-name()',
ring_num for ordinality,
nodes xmltype path '//posList/..'
) x1
cross join xmltable (
xmlnamespaces(default 'http://www.opengis.net/gml/'),
'/*'
passing x1.nodes
columns parent varchar2(21) path './name()',
coordinates varchar2(30) path 'posList'
) x2;
which получает:
TYPE RING_NUM PARENT COORDINATES
-------- ---------- --------------------- ------------------------------
exterior 1 gml:LinearRing [coordinates]
interior 2 gml:LineStringSegment [coordinates]
interior 2 gml:Arc [coordinates]
interior 2 gml:LineStringSegment ...
interior 3 gml:LinearRing [coordinates]
Переключение между name()
и local-name()
позволяет вам включать или опускать пространство имен из значения.
Вы также можете сделать это с одним XMLTable, но получение «номера звонка» немного проблематично; здесь я внедряю атрибут во внешний / внутренний узел - который может быть медленнее, чем цепной подход XMLTable, но, возможно, стоит проверить ваши данные:
select x.type, x.ring_num, x.parent, x.coordinates
from xmltable(
xmlnamespaces(default 'http://www.opengis.net/gml/'),
'copy $i := /Polygon
modify
for $j in $i/(exterior | interior)
return (insert node attribute pos { count($j/preceding-sibling::*) + 1 } into $j)
return $i//posList'
passing t.p_xml
columns type varchar2(8) path 'local-name(./ancestor::exterior | ./ancestor::interior)',
ring_num number path '(./ancestor::exterior/@pos | ./ancestor::interior/@pos)',
parent varchar2(21) path '../name()',
coordinates varchar2(30) path '.'
) x;
С помощью CTE для выборочных данных снова получает те же результаты. Я не уверен, есть ли другой способ - эффективно - счетчик итераций в FLWOR l oop.