Как вытащить массив простого типа из XML в PLSQL

Основная особенность: высокоуровневые конструкции, которые возвращали бы последовательность
элементов по XPath или XQuery можно использовать только SQL-запросе. Они не работають в “чистом” PL/SQL.
Если стоит задача парсить XML, не используя select’ы вообще, то для извлечения скалярных значений
можно пользоваться extract(xmltype(‘xml text’), ‘some XPath’). Но чтобы получить однородный массив,
придется использовать XMLDOM API, как во 2-м примере.

Следует учитывать, что xmlsequence объявлена как deprecated.
Наиболее гибкий и мощный способ преборазования XML в массивы и таблицы – это XQuery через XmlTable.

1. Через преобразование результата XPath к xmlsequence в SQL-запросе:

select
 value(t).getClobVal(),
 (select extract(value(t),to_char('/*/@'||'connects')).getClobVal() from dual),
 (select extract(value(t),to_char('/*/text()')).getClobVal() from dual)
 from table(xmlsequence(extract(xmltype('<packet id="3073653">
  <contract value="669752/NIC-D"/>
  <subd name="oracle" connects="100"/>
  <subd name="oracle" connects="100"/>
  <subd name="mysql" connects="10"/>
  <email value="box@nicmail.ru"/>
  <hcp-access value="on"/>
  <hdns>
  <on value="vasia.ru"/>
  <on value="masha.ru"/>
  <off value="gazdarmaku.net"/>
  <not-hosting-dns value="hdns.net"/>
  </hdns>
 </packet>
 '),'/packet/subd[attribute::name="oracle" and attribute::connects>1 and attribute::connects<101]')))

2. С помощью XMLDOM API:

declare
  xml XMLType := XMLType('<packet id="3073653">
 <contract value="669752/NIC-D"/>
 <subd name="oracle" connects="100"/>
 <subd name="oracle" connects="100"/>
 <subd name="mysql" connects="10"/>
 <email value="box@nicmail.ru"/>
 <hcp-access value="on"/>
 <hdns>
 <on value="vasia.ru"/>
 <on value="masha.ru"/>
 <off value="gazdarmaku.net"/>
 <not-hosting-dns value="hdns.net"/>
 </hdns>
 </packet>');
  x dbms_xmldom.DOMNodeList;
  node dbms_xmldom.DOMNode;
  value varchar2(32000);
  i pls_integer;
 begin
  x :=
 dbms_xmldom.getChildNodes(dbms_xmldom.getNodeFromFragment(xml.extract('//*[@connects]')));
  dbms_output.put_line(dbms_xmldom.getLength(x) );
  for i in 0..dbms_xmldom.getLength(x)-1 loop
  node := dbms_xmldom.item(x, i);
  dbms_output.put_line(
  dbms_xmldom.getNodeValue(
  dbms_xmldom.getNamedItem(
  dbms_xmldom.getAttributes(node)
  , 'connects'
  )
  )
  );
  end loop;
 end;

3. С помощью XQuery в конструкции XmlTable:

declare
l_t xmltype := xmltype(‘<packet id=”3073653″>
<contract value=”669752/NIC-D”/>
<subd name=”oracle” connects=”100″/>
<subd name=”oracle” connects=”100″/>
<subd name=”mysql” connects=”10″/>
<email value=”box@nicmail.ru”/>
<hcp-access value=”on”/>
<hdns>
<on value=”vasia.ru”/>
<on value=”masha.ru”/>
<off value=”gazdarmaku.net”/>
<not-hosting-dns value=”hdns.net”/>
</hdns>
</packet>’);
l_p xmltype;
begin

for p in (SELECT cc v from XMLTable(
‘for $i in /packet/subd[attribute::name=”oracle” and attribute::connects>1 and attribute::connects<101]
return $i’
PASSING l_t
COLUMNS cc number path ‘@connects’) xtab)
loop
dbms_output.put_line(p.v * 2);
end loop;

end;