我已经给出了下表。此表包含xml标记和值以及可选的父标记引用。
CREATE GLOBAL TEMPORARY TABLE XML_TAG_VAL
(
OBJ_ID NUMBER, -- unique for one whole xml document
ID NUMBER, -- unique for every tag
TAG VARCHAR2(1000 BYTE), -- tags name
VAL CLOB, -- tags value
LVL NUMBER, -- depth of the tag
ATTR_ID NUMBER, -- foreign key to tag_attr table (do this later)
PARENT_ID NUMBER -- id of parent tag (xml_tag_val.id)
)
ON COMMIT DELETE ROWS
NOCACHE;
让我们在此表中插入一些非常简单的测试数据......
insert into xml_tag_val values(1,1,'a',null,1,null,null);
insert into xml_tag_val values(1,2,'b','b-value',2,null,1);
insert into xml_tag_val values(1,3,'b','b-value 2',2,null,1);
我现在要做的是为给定的客户端接口生成XML。所以结果应该是:
<a>
<b>b-value</b>
<b>b-value 2</b>
</a>
因此对于这个特定情况,使用xmlelement的手工制作的sql不会成为问题。但是如何在不知道路径有多深的情况下选择xml树呢?我所知道的只是每个孩子都指向其父母。
编辑1:
我发现有一种方法可以使用递归查询来构建XML,我有以下查询:
declare
l_qry_ctx dbms_xmlgen.ctxhandle;
l_result clob;
l_obj_id number := 1;
begin
l_qry_ctx := dbms_xmlgen.newcontextFromHierarchy('
select level,xmlelement(tag, val)
from oranetted_plugin.xml_tag_val
where obj_id = ' || l_obj_id || '
start with parent_id is null
connect by parent_id = prior id'
);
l_result:=dbms_xmlgen.getxml(l_qry_ctx);
dbms_output.put_line(l_result);
end;
/
问题是无法从sqls结果中提供标签名称。标签不是“a”或“b”,而是显示为“标签”。
<TAG>
<TAG>b-value</TAG>
<TAG>b-value 2</TAG>
</TAG>
有什么想法来解决这个问题吗?
答案 0 :(得分:0)
好的,这很难看,但可能会得到理想的结果
declare
l_qry_ctx dbms_xmlgen.ctxhandle;
l_result clob;
l_expression varchar2(32767);
l_obj_id number := 1;
begin
for r in (select distinct tag from xml_tag_val) loop
l_expression := l_expression || ' when ''' || r.tag ||
''' then xmlelement(' || r.tag || ',val)';
end loop;
l_expression := 'case tag ' || l_expression || ' end';
l_qry_ctx := dbms_xmlgen.newcontextFromHierarchy('
select level,' ||
l_expression || '
from xml_tag_val
where obj_id = ' ||
l_obj_id || '
start with parent_id is null
connect by parent_id = prior id');
l_result := dbms_xmlgen.getxml(l_qry_ctx);
dbms_output.put_line(l_result);
end;
/
...但是你必须记住CASE表达式限制。
答案 1 :(得分:0)
Marcin带领我走向正确的方向,谢谢!
如果有人遇到类似问题,您可以使用函数而不是构建大案例语句。所以这是我最后的工作解决方案:
create or replace
function calc_xml_element(
i_tag varchar2
,i_val clob
,i_attr_id number := null
) return xmltype
is
l_res xmltype;
l_sql varchar2(4000);
l_attr_sql varchar2(4000) := 'XMLATTRIBUTES(';
begin
if i_attr_id is not null then
for tupl in
(select * from xml_tag_attr where id = i_attr_id)
loop
l_attr_sql := l_attr_sql || '''' || substr(tupl.attr_val,1,255) || ''' as "' || tupl.attr || '",';
end loop;
l_attr_sql := rtrim(l_attr_sql,',') || ')';
l_sql := 'begin select xmlelement("' || i_tag || '",' || l_attr_sql || ',:val) into :a from dual; end;';
else
l_sql := 'begin select xmlelement("' || i_tag || '",:val) into :a from dual; end;';
end if;
execute immediate l_sql
using in i_val, in out l_res;
return l_res;
exception when others then
raise_application_error(-20000,'Calc XML failed ' || l_sql, true);
end calc_xml_element;
/
现在你可以做到:
insert into oranetted_plugin.xml_tag_val values(1,1,'a',null,1,null,null);
insert into oranetted_plugin.xml_tag_val values(1,2,'b','b-value',2,null,1);
insert into oranetted_plugin.xml_tag_val values(1,3,'b','b-value 2',null,1,1);
declare
l_qry_ctx dbms_xmlgen.ctxhandle;
l_result clob;
l_obj_id number := 1;
begin
l_qry_ctx := dbms_xmlgen.newcontextFromHierarchy('
select level, oranetted_plugin.calc_xml_element(tag,val,attr_id) ' ||
'from oranetted_plugin.xml_tag_val
where obj_id = ' || l_obj_id || '
start with parent_id is null
connect by parent_id = prior id');
l_result := dbms_xmlgen.getxml(l_qry_ctx);
dbms_output.put_line(l_result);
end;
/