如何在Oracle中解决复杂的XMLELEMENT

时间:2018-11-12 11:20:55

标签: xml plsql oracle11g

问题

XML

<logs>
    <log>
        <ID>123456</ID>
        <NAME>TEST</NAME>
    </log>
</logs>
<logs>
    <log>
        <ID>1234567</ID>
        <NAME>TEST1</NAME>
    </log>
</logs>
上面的xml日志中的

即将在log标记后关闭。

但是我需要XML,其中日志标记在下面的xml中关闭。

<logs>
    <log>
        <ID>123456</ID>
        <NAME>TEST</NAME>
    </log>
    <log>
        <ID>1234567</ID>
        <NAME>TEST1</NAME>
    </log>
</logs>

我尝试过的代码

v_output是clob类型的输出变量。

BEGIN
    x := XMLType (in_xml);

    FOR r IN (SELECT EXTRACTVALUE (VALUE (p), '/log/id/text()') AS log_id
                FROM TABLE (XMLSEQUENCE (EXTRACT (x, '/logs/log'))) p)
    LOOP
        OPEN cursorname (r.id);

        FETCH cursorname INTO tmp;

        -- fetching columns
        IF cursorname%FOUND
        THEN
            SELECT XMLELEMENT ("logs",
                               XMLELEMENT ("log", XMLFOREST (id, name))).GETCLOBVAL ()
              INTO out_xml
              FROM  view where id in ( rec1.id ) ;

            v_output := out_xml;
            DBMS_OUTPUT.PUT_LINE (v_output);
        END IF;

        CLOSE cursorname;
    END LOOP;
  • 谁能建议我如何使用xmlelement解决多个xml元素。

  • 输入是XML,解析xml输出后应该是xml。

  • 如果我需要Dyanamic XML,可以在下面使用代码。

    select xmltype(cursor(select * from view )) from dual;
    
  • 光标在循环中。

  • 任何建议都是最欢迎的。

1 个答案:

答案 0 :(得分:3)

如果我了解您要做什么,那么您是从XML文档的字符串版本开始的,例如:

<logs><log><ID>123456</ID></log><log><ID>1234567</ID></log></logs>

,并尝试添加与从视图中获得的每个name值相对应的id值。

您可以使用XMLTable提取所有ID,将其加入视图,然后通过XMLAgg重建最终的XML,例如:

select xmlelement("logs", xmlagg(xmlelement("log", xmlforest(v.id, v.name)))).getclobval()
into out_xml
from xmltable(
  '/logs/log'
  passing xmltype(in_xml)
  columns id number path 'ID'
) x
join your_view v on v.id = x.id;

作为从字符串开始的纯SQL演示,并带有CTE来代表您的视图:

-- CTE to represent your view
with your_view (id, name) as (
  select 123456, 'TEST' from dual
  union all
  select 1234567, 'TEST1' from dual
)
-- actual query
select xmlelement("logs", xmlagg(xmlelement("log", xmlforest(v.id, v.name)))).getclobval()
from xmltable(
  '/logs/log'
  passing xmltype('<logs><log><ID>123456</ID></log><log><ID>1234567</ID></log></logs>')
  columns id number path 'ID'
) x
join your_view v on v.id = x.id;

XMLELEMENT("LOGS",XMLAGG(XMLELEMENT("LOG",XMLFOREST(V.ID,V.NAME)))).GETCLOBVAL()                     
-----------------------------------------------------------------------------------------------------
<logs><log><ID>123456</ID><NAME>TEST</NAME></log><log><ID>1234567</ID><NAME>TEST1</NAME></log></logs>

或序列化以美化它:

-- CTE to represent your view
with your_view (id, name) as (
  select 123456, 'TEST' from dual
  union all
  select 1234567, 'TEST1' from dual
)
-- actual query
select xmlserialize(document
  xmlelement("logs", xmlagg(xmlelement("log", xmlforest(v.id, v.name))))
  indent) as out_xml
from xmltable(
  '/logs/log'
  passing xmltype('<logs><log><ID>123456</ID></log><log><ID>1234567</ID></log></logs>')
  columns id number path 'ID'
) x
join your_view v on v.id = x.id;

OUT_XML                                                                         
--------------------------------------------------------------------------------
<logs>
  <log>
    <ID>123456</ID>
    <NAME>TEST</NAME>
  </log>
  <log>
    <ID>1234567</ID>
    <NAME>TEST1</NAME>
  </log>
</logs>

如果您确实想使用链接到的问题中显示的机制,则可以通过将循环内生成的每个元素附加到循环的外部,并在其外部添加开始和结束logs标记,来构建最终输出CLOB。循环:

declare
  in_xml clob := '<logs><log><ID>123456</ID></log><log><ID>1234567</ID></log></logs>';
  out_xml clob;
  v_output clob;
begin
  v_output := '<logs>';
  for r in (
    select id
    from xmltable(
      '/logs/log'
      passing xmltype(in_xml)
      columns id number path 'ID'
    )
  )
  loop
     select xmlelement("log", xmlforest (id, name)).getclobval()
     into out_xml
     from your_view where id = r.id;

     v_output := v_output || out_xml;
  end loop;
  v_output := v_output || '</logs>';
  dbms_output.put_line (v_output);
end;
/

<logs><log><ID>123456</ID><NAME>TEST</NAME></log><log><ID>1234567</ID><NAME>TEST1</NAME></log></logs>


PL/SQL procedure successfully completed.

但是避免光标循环并只加入一次会更简单:

declare
  in_xml clob := '<logs><log><ID>123456</ID></log><log><ID>1234567</ID></log></logs>';
  v_output clob;
begin
  select xmlelement("logs", xmlagg(xmlelement("log", xmlforest(v.id, v.name)))).getclobval()
  into v_output
  from xmltable(
    '/logs/log'
    passing xmltype(in_xml)
    columns id number path 'ID'
  ) x
  join your_view v on v.id = x.id;

  dbms_output.put_line (v_output);
end;
/

<logs><log><ID>123456</ID><NAME>TEST</NAME></log><log><ID>1234567</ID><NAME>TEST1</NAME></log></logs>


PL/SQL procedure successfully completed.