XML-иерархия Oracle с дочерними узлами (NEWCONTEXTFROMHIERARCHY) - PullRequest
1 голос
/ 06 марта 2019

Моя цель - XML документ, подобный этому:

<?xml version="1.0" encoding="UTF-8"?>
<IMPORT>
  <PGR name="Product Group 1">
    <PGR name="Product Group 1-1">
      <PGR name="Product Group 1-1-1">
        <PRO name="Product X">
          <PRV name="Product Variant X-1" />
        </PRO>
      </PGR>
    </PGR>
  </PGR>
</IMPORT>

Мои таблицы с примерами данных:

create table PRODUCTS
(
  id             NUMBER(8) not null,
  name           VARCHAR2(100),
  baseproduct    VARCHAR2(100),
  productgroupid NUMBER(8)
);

insert into PRODUCTS (ID, NAME, BASEPRODUCT, PRODUCTGROUPID)
values (1, 'Product Variant 1', 'Product X', 3);

create table PRODUCTGROUPS
(
  id       NUMBER(8) not null,
  parentid NUMBER(8),
  name     VARCHAR2(100)
);

insert into PRODUCTGROUPS (ID, PARENTID, NAME)
values (1, null, 'Product Group 1');

insert into PRODUCTGROUPS (ID, PARENTID, NAME)
values (2, 1, 'Product Group 1-1');

insert into PRODUCTGROUPS (ID, PARENTID, NAME)
values (3, 2, 'Product Group 1-1-1');

insert into PRODUCTGROUPS (ID, PARENTID, NAME)
values (4, null, 'Product Group 2');

insert into PRODUCTGROUPS (ID, PARENTID, NAME)
values (5, 4, 'Product Group 2-1');

insert into PRODUCTGROUPS (ID, PARENTID, NAME)
values (6, 5, 'Product Group 2-1-1');

Каждый PRODUCT (PRV-узел) имеет BASEPRODUCT (PRO-узел) и PRODUCTGROUP (PGR-узел). PRODUCTGROUPS являются иерархическими.

Я получаю XML для PRODUCTGROUP-Hierarchy с:

select DBMS_XMLGEN.GETXMLTYPE(DBMS_XMLGEN.NEWCONTEXTFROMHIERARCHY('
select level, xmlelement("PGR", XMLATTRIBUTES(NAME)) 
from PRODUCTGROUPS
start with PARENTID is null
connect by nocycle PARENTID = PRIOR ID')) from dual

У меня также есть желаемая XML-структура, но без иерархии PRODUCTGROUP:

select P.ID,
  XMLROOT(
    XMLELEMENT("IMPORT",  
      XMLELEMENT("PGR", XMLATTRIBUTES(G.NAME as "name"),
        XMLELEMENT("PRO", XMLATTRIBUTES(P.BASEPRODUCT as "name"),
          XMLELEMENT("PRV", XMLATTRIBUTES(P.NAME as "name"))
        )   
      )        
    ) 
, version '1.0" encoding="utf-8') as XML
from PRODUCTS P join PRODUCTGROUPS G on P.PRODUCTGROUPID = G.ID

Теперь я не знаю, как объединить эти два подхода, чтобы получить желаемый XML-Structure с PRODUCTGROUP-Hierarchy. Есть ли способ получить это с Oracle-XML-Functions?

1 Ответ

0 голосов
/ 06 марта 2019

Если честно, я никогда не видел эту функцию (NEWCONTEXTFROMHIERARCHY), но это то, что мне удалось сделать. Я сделал функцию, которая создает необходимую часть иерархического дерева и объединяет два дополнительных параметра (базовый продукт и продукт). Тогда я использовал newcontextfromhierarchy. Таким образом, функция возвращает весь узел.

create or replace function xml_hier(i_id in varchar2, i_base in varchar2, i_name in varchar2) return xmltype is
  v_ret xmltype;
begin
  select dbms_xmlgen.getxmltype(dbms_xmlgen.newcontextfromhierarchy('
    with t as (
      select level lvl, xmlelement("PGR", XMLATTRIBUTES(NAME))
        from PRODUCTGROUPS
        where id in (select id 
                       from PRODUCTGROUPS
                       connect by prior PARENTID = ID start with id = '||i_id||')
        connect by PARENTID = prior ID
        start with parentid is null)
    select * from t 
    union all
    select (select max(lvl) + 1 from t), XMLELEMENT("PRO", XMLATTRIBUTES('''||i_base||''' as "name")) from dual
    union all
    select (select max(lvl) + 2 from t), XMLELEMENT("PRV", XMLATTRIBUTES('''||i_name||''' as "name")) from dual'))
  into v_ret
  from dual;
  return v_ret;
end;

Итак, когда ваши таблицы созданы, я запускаю:

select p.id,
       xmlroot(
         xmlelement("IMPORT",  
           xml_hier(g.id, p.baseproduct, p.name))
         , version '1.0" encoding="utf-8') as xml
  from products p 
  join productgroups g on p.productgroupid = g.id;

и результат:

<?xml version="1.0" encoding="utf-8"?>
<IMPORT>
  <PGR NAME="Product Group 1">
    <PGR NAME="Product Group 1-1">
      <PGR NAME="Product Group 1-1-1">
        <PRO name="Product X">
          <PRV name="Product Variant 1"/>
        </PRO>
      </PGR>
    </PGR>
  </PGR>
</IMPORT>

Иерархический запрос сначала работает в обратном направлении, чтобы найти предков. Затем все идет нормально, используя только уже известные id.

Надеюсь, это поможет:)

...