在PostgreSQL函数中生成来自变量和表的XML

时间:2013-02-22 20:21:09

标签: xml function postgresql

我将从我想要的输出开始:

<?xml version="1.0"?>
<Accounts>
    <Account>
        <variable1>variable1</variable1>
        <variable2>variable2</variable2>
        <variable3>variable3</variable3>
        <variable4>variable4</variable4>
        <variable5>variable5</variable5>
        <variable6>variable6</variable6>
        <Table>
            <Row>
                <Column1>row1col1</Column1>
                <Column2>row1col2</Column2>
                <Column3>row1col3</Column3>
            </Row>
            <Row>
                <Column1>row2col1</Column1>
                <Column2>row2col2</Column2>
                <Column3>row2col3</Column3>
            </Row>
            <Row>
                <Column1>row3col1</Column1>
                <Column2>row3col2</Column2>
                <Column3>row3col3</Column3>
            </Row>
        </Table>
    </Account>
    ...
</Accounts>

这需要来自当前循环帐户的SQL函数,并且每个帐户ID收集上述每个帐户的所有相关数据,例如:变量1,2,表等。因此,根据帐户ID,它返回所有变量以及包含3列和所有行的表。

因此,为简化起见,对于每个帐户ID,XML文件都需要将上述结构附加到文件中。现在,当我尝试使用所有这些不同的部分创建XML文件时,我的困境就出现了。

第一个问题是如何将表信息和变量信息组合到一个XML树中。我知道可以从表中创建带有元素的XML林,但问题是每个帐户都有一组可变数据和一个表。我已经考虑了table_to_xml,但这直接来自一个表,我不知道如何在table / xml之前附加变量元素。

我考虑过做文本数组:

for rec in execute cmd
loop

  cmd:= 'select xmlelement(name "Account",
        xmlelement(name "Variable1", '||var1||'))';

  execute cmd into vtext
  varray[n] := vtext;
  n++
end loop;

然后可能将嵌套在xmlelement中的表作为文本数组。继续嵌套,直到我拥有所有的为止,然后在它们结合在一起后将它们发送给XML。

下一个问题是将所有这些帐户合并到同一XML文件中的一个总体元素中。

如果有人对如何解决这个问题有任何想法,我将非常感谢帮助。我觉得我在思考整个过程,或者在SQL中做起来太荒谬了,也许我应该用像Python这样的脚本语言来尝试这些操作。

1 个答案:

答案 0 :(得分:0)

问题的解决方案非常简单。将所有数据放入临时表并连接。特别是为我想要的输出做这个的方法:

-- FUNCTION AFTER CREATE AND DECLARES
v_cmd := 'select Accounts from <table>';

final_xml := '<?xml version="1.0"?><Accounts>';

for record in execute v_cmd
loop
    <generate Account data into SQL variables>

    -- Check if temp table exists, then create P1
    v_table_name1 := '<temp_table1>';

    IF EXISTS (select 1 from information_schema.tables 
    where table_schema = '<schema>' and table_name = <temp_table1>) THEN
        v_s_cmd := 'DROP TABLE '||<temp_table1>;
        execute v_s_cmd;
    END IF;

    v_s_cmd := 'CREATE TABLE <temp_table1>
    (variable1 varchar, variable2 varchar, ...)';
    execute v_s_cmd;
    v_s_cmd := 'INSERT INTO <temp_table1> 
    (variable1, variable2, ...)
    VALUES ('||coalesce(quote_literal(Account.variable1),'NULL')||',' 
           ''||coalesce(quote_literal(Account.variable2),'NULL')||',' ...)'';
    execute v_s_cmd;

    <generate multiple row data to be elements of the above Account>

    -- Check if temp table exists, then create P1
    v_table_name2 := '<temp_table2>';

    IF EXISTS (select 1 from information_schema.tables 
    where table_schema = '<schema>' and table_name = <temp_table2>) THEN
        v_s_cmd := 'DROP TABLE '||<temp_table2>;
        execute v_s_cmd;
    END IF;

    v_s_cmd := 'CREATE TABLE <temp_table2(Column1, Column2, Column3)';
    execute v_s_cmd;

    column_id = record.row_id;

    for column_record in

    SELECT Column1, Column2, Column3 FROM <column_data_source>
    WHERE data_id = column_id ORDER BY Column1, Column2, Column3

    loop
        v_s_cmd := 'INSERT INTO '||<temp_table2>|| 
        '(Column1, Column2, Column3, column_id) SELECT 
        '||quote_literal(column_record.Column1)||', 
        '||quote_literal(column_record.Column2)||', 
        '||quote_literal(column_record.Column2)||', 
        '''||column_id||''';';
        execute v_s_cmd;
    end loop;

    -- get var data 
    v_s_cmd := '(select regexp_replace((
    XMLElement(name Account, 
        XMLForest(variable1, variable2 ...)))::text,
        ''</Account>'','''',''g'') as var_d
    FROM <temp_table1>)';

    execute v_s_cmd into var_data;

    -- get Table data
    v_s_cmd := 'select XMLElement(name Row, 
                    XMLForest(Column1, Column2, Column3)) as test
                FROM '||<temp_table2>;

    table_rec := '<Table>';

    -- concatenate to variable
    for row_rec in execute v_s_cmd
    loop
        table_rec := table_rec || row_rec.test;
    end loop;
    table_rec := table_rec||'</Table></Account>';

    -- complete XML part and concatenate to main xml variable
    final_xml := final_xml || var_data || s_a_rec;

    v_s_cmd := 'drop table '||temp_table1;
    execute v_s_cmd;
    v_s_cmd := 'drop table '||temp_table2;
    execute v_s_cmd;

END LOOP;

final_xml := final_xml || '</Accounts>';

final_xml := XMLPARSE(DOCUMENT final_xml);

create table schema.temp_final_xml(xmlcode varchar);
insert into schema.temp_final_xml(xmlcode) VALUES (final_xml);

v_s_cmd := 'COPY (select xmlcode from schema.temp_final_xml) 
            TO ''/filepath/file.xml''';
execute v_s_cmd;

drop table schema.temp_final_xml;

如果有更简洁的方法来执行此操作,我很想知道。我把我的大脑震撼了几天才想出来。