使用 PL/SQL 创建 XML

Posted

技术标签:

【中文标题】使用 PL/SQL 创建 XML【英文标题】:Creating XML with PL/SQL 【发布时间】:2017-01-13 23:16:49 【问题描述】:

我需要用 PL/SQL 创建 XML,我的解决方案中有两个问题。

示例代码如下所示:

select xmlelement( 
    "tag_one",
    XMLAGG(
        xmlelement("user", 
            xmlforest( 
                'something' "two"
                , 'else' "tree"
                , NULL "four" 
                , ( 
                    select sys_xmlagg( 
                        xmlelement( 
                            "secondGoup", 
                            xmlforest(
                                'true' "five"
                                , 123 "six"
                            ) 
                        ) 
                    ) 
                    FROM dual
                ) "group_tag" 
            )
        )
    ) 
) as "XML_QUERY" 
FROM dual

我得到的 XML 看起来像这样

<tag_one>
    <user>
        <two>something</two>
        <tree>else</tree>
        <group_tag>
            <ROWSET>
                <secondGoup>
                    <five>true</five>
                    <six>123</six>
                </secondGoup>
            </ROWSET>
        </group_tag>
    </user>
</tag_one>

它的问题是:

1.) 我不需要 ROWSET 标签,也不知道如何删除它

2.) 我的 XML 中需要空标记 4

<four></four>

我应该提到可以有多个 secondGoup 标签,但是这段代码可以毫无问题地生成它们

注意以防万一您有更好的方法来创建此 XML

<tag_one>
    <user>
        <two>something</two>
        <tree>else</tree>
        <four></four>
        <group_tag>
            <secondGoup>
                <five>true</five>
                <six>123</six>
            </secondGoup>
            <secondGoup>
                <five>true</five>
                <six>456</six>
            </secondGoup>
            <secondGoup>
                <five>false</five>
                <six>789</six>
            </secondGoup>
        </group_tag>
    </user>
</tag_one>

5 和 6 的查询如下所示

SELECT t1.field1 "five"
, t2.field2 "six"
FROM table1 t1
JOIN table2 t2 ON t1.field4 = t2.field2
WHERE t2.field3 = 3

这会返回 X 行(有时返回 1,有时返回 2、3、20,...)。在WHERE中添加3作为例子,实际查询中存在变量值

【问题讨论】:

【参考方案1】:

你好,你的意思是得到这个输出:

<tag_one>
    <user>
        <two>something</two>
        <tree>else</tree>
        <four></four>
        <group_tag>
            <secondGoup>
                <five>true</five>
                <six>123</six>
            </secondGoup>
            <secondGoup>
                <five>true</five>
                <six>456</six>
            </secondGoup>
            <secondGoup>
                <five>true</five>
                <six>789</six>
            </secondGoup>
        </group_tag>
    </user>
</tag_one>

这是正确的查询:

SELECT XMLELEMENT (
          "tag_one",
          XMLAGG (
             XMLELEMENT (
                "user",
                XMLFOREST (
                   'something' "two",
                   'else' "tree",
                   '' "four",
                   XMLFOREST (
                      XMLFOREST ('true' "five", 123 "six") "secondGoup",
                      XMLFOREST ('true' "five", 456 "six") "secondGoup",
                      XMLFOREST ('true' "five", 789 "six") "secondGoup") "group_tag"))))
          AS "XML_QUERY"
  FROM DUAL

===========编辑==================

您好,再次,对于您的动态查询,我们不再可以使用 XMLELEMT 和相关函数,因为它们将返回 clob,使用它们会很麻烦,我在这里为您找到了一个很长的 pl/sql 块(它是太大太复杂了,但我让它适用于你的情况):

DECLARE
   L_XMLTYPE             XMLTYPE;
   L_DOMDOC              DBMS_XMLDOM.DOMDOCUMENT;
   L_ROOT_NODE           DBMS_XMLDOM.DOMNODE;

   L_SUPP_NUM_ELEMENT    DBMS_XMLDOM.DOMELEMENT;
   L_SUPP_NAME_ELEMENT   DBMS_XMLDOM.DOMELEMENT;

   L_SUPP_NUM_NODE       DBMS_XMLDOM.DOMNODE;
   L_SUPP_NAME_NODE      DBMS_XMLDOM.DOMNODE;

   L_SUPP_NUM_TNODE      DBMS_XMLDOM.DOMNODE;
   L_SUPP_NAME_TNODE     DBMS_XMLDOM.DOMNODE;

   L_SUPP_NUM_TEXT       DBMS_XMLDOM.DOMTEXT;
   L_SUPP_NAME_TEXT      DBMS_XMLDOM.DOMTEXT;

   L_C1                  DBMS_XMLDOM.DOMELEMENT;
   L_C1_NODE             DBMS_XMLDOM.DOMNODE;

   L_C2                  DBMS_XMLDOM.DOMELEMENT;
   L_C2_NODE             DBMS_XMLDOM.DOMNODE;

   L_C2_TEXT             DBMS_XMLDOM.DOMTEXT;
   L_C2_TEXT_NODE        DBMS_XMLDOM.DOMNODE;

   L_SUPPLIER_ELEMENT    DBMS_XMLDOM.DOMELEMENT;
   L_SUPPLIER_NODE       DBMS_XMLDOM.DOMNODE;
   L_SUP_NODE            DBMS_XMLDOM.DOMNODE;
BEGIN
   -- Create an empty XML document
   L_DOMDOC := DBMS_XMLDOM.NEWDOMDOCUMENT;

   -- Create a root node
   L_ROOT_NODE := DBMS_XMLDOM.MAKENODE (L_DOMDOC);

   -- Create a new Supplier Node and add it to the root node
   L_SUP_NODE :=
      DBMS_XMLDOM.APPENDCHILD (
         L_ROOT_NODE,
         DBMS_XMLDOM.MAKENODE (
            DBMS_XMLDOM.CREATEELEMENT (L_DOMDOC, 'tag_one')));


   L_C1 := DBMS_XMLDOM.CREATEELEMENT (L_DOMDOC, 'user');
   L_C1_NODE :=
      DBMS_XMLDOM.APPENDCHILD (L_SUP_NODE, DBMS_XMLDOM.MAKENODE (L_C1));

   L_C2 := DBMS_XMLDOM.CREATEELEMENT (L_DOMDOC, 'two');
   L_C2_NODE :=
      DBMS_XMLDOM.APPENDCHILD (L_C1_NODE, DBMS_XMLDOM.MAKENODE (L_C2));

   L_C2_TEXT := DBMS_XMLDOM.CREATETEXTNODE (L_DOMDOC, 'something');
   L_C2_TEXT_NODE :=
      DBMS_XMLDOM.APPENDCHILD (L_C2_NODE, DBMS_XMLDOM.MAKENODE (L_C2_TEXT));

   L_C2 := DBMS_XMLDOM.CREATEELEMENT (L_DOMDOC, 'three');
   L_C2_NODE :=
      DBMS_XMLDOM.APPENDCHILD (L_C1_NODE, DBMS_XMLDOM.MAKENODE (L_C2));

   L_C2_TEXT := DBMS_XMLDOM.CREATETEXTNODE (L_DOMDOC, 'else');
   L_C2_TEXT_NODE :=
      DBMS_XMLDOM.APPENDCHILD (L_C2_NODE, DBMS_XMLDOM.MAKENODE (L_C2_TEXT));

   L_C2 := DBMS_XMLDOM.CREATEELEMENT (L_DOMDOC, 'group_tag');
   L_C2_NODE :=
      DBMS_XMLDOM.APPENDCHILD (L_C1_NODE, DBMS_XMLDOM.MAKENODE (L_C2));

   FOR SUP_REC IN (SELECT T1.FIELD1, T2.FIELD2
                     FROM TABLE1 T1 JOIN TABLE2 T2 ON T1.FIELD4 = T2.FIELD2
                    WHERE T2.FIELD3 = 3)
   LOOP
      -- For each record, create a new Supplier element
      -- and add this new Supplier element to the Supplier Parent node
      L_SUPPLIER_ELEMENT := DBMS_XMLDOM.CREATEELEMENT (L_DOMDOC, 'secondGoup');
      L_SUPPLIER_NODE :=
         DBMS_XMLDOM.APPENDCHILD (
                                  L_C2_NODE,
                                  DBMS_XMLDOM.MAKENODE (L_SUPPLIER_ELEMENT)
                                 );

      -- Each Supplier node will get a Number node which contains the Supplier Number as text
      L_SUPP_NUM_ELEMENT := DBMS_XMLDOM.CREATEELEMENT (L_DOMDOC, 'five');
      L_SUPP_NUM_NODE :=
         DBMS_XMLDOM.APPENDCHILD (
                                  L_SUPPLIER_NODE,
                                  DBMS_XMLDOM.MAKENODE (L_SUPP_NUM_ELEMENT)
                                 );
      L_SUPP_NUM_TEXT := DBMS_XMLDOM.CREATETEXTNODE (L_DOMDOC, SUP_REC.FIELD1);
      L_SUPP_NUM_TNODE :=
         DBMS_XMLDOM.APPENDCHILD (
                                  L_SUPP_NUM_NODE,
                                  DBMS_XMLDOM.MAKENODE (L_SUPP_NUM_TEXT)
                                 );

      -- Each Supplier node will get a Name node which contains the Supplier Name as text
      L_SUPP_NAME_ELEMENT := DBMS_XMLDOM.CREATEELEMENT (L_DOMDOC, 'six');
      L_SUPP_NAME_NODE :=
         DBMS_XMLDOM.APPENDCHILD (
                                  L_SUPPLIER_NODE,
                                  DBMS_XMLDOM.MAKENODE (L_SUPP_NAME_ELEMENT)
                                 );
      L_SUPP_NAME_TEXT :=
         DBMS_XMLDOM.CREATETEXTNODE (L_DOMDOC, SUP_REC.FIELD2);
      L_SUPP_NAME_TNODE :=
         DBMS_XMLDOM.APPENDCHILD (
                                  L_SUPP_NAME_NODE,
                                  DBMS_XMLDOM.MAKENODE (L_SUPP_NAME_TEXT)
                                 );
   END LOOP;

   L_XMLTYPE := DBMS_XMLDOM.GETXMLTYPE (L_DOMDOC);
   DBMS_XMLDOM.FREEDOCUMENT (L_DOMDOC);

   DBMS_OUTPUT.PUT_LINE (L_XMLTYPE.GETCLOBVAL);
END;

输出:

<tag_one>
  <user>
    <two>something</two>
    <three>else</three>
    <group_tag>
      <secondGoup>
        <five>123</five>
        <six>014</six>
      </secondGoup>
      <secondGoup>
        <five>456</five>
        <six>011</six>
      </secondGoup>
      <secondGoup>
        <five>789</five>
        <six>011</six>
      </secondGoup>
      <secondGoup>
        <five>012</five>
        <six>011</six>
      </secondGoup>
      <secondGoup>
        <five>345</five>
        <six>011</six>
      </secondGoup>
      <secondGoup>
        <five>678</five>
        <six>011</six>
      </secondGoup>
      <secondGoup>
        <five>901</five>
        <six>011</six>
      </secondGoup>
      <secondGoup>
        <five>234</five>
        <six>011</six>
      </secondGoup>
      <secondGoup>
        <five>567</five>
        <six>011</six>
      </secondGoup>
    </group_tag>
  </user>
</tag_one>

【讨论】:

请注意不要通过NULL来创建空标签,可以使用NVL()函数来转换可能的NULL 随心所欲。 漂亮,没有行集标签,喜欢它:) 只是一件事,应该用单独的查询提取 5 和 6 的值(并且它们有不同的行数),不知道我该怎么做这里。在原帖中添加示例 @BeRightBack 您能否添加一个包含五个和六个值的示例查询? 我使用了这个链接中的代码:quest4apps.com/create-xml-using-dbms_xmldom 太棒了!!!刚刚使用 dbms_xmldom 编写,就像魅力一样,谢谢。顺便说一句,它一点也不复杂,它很简单,只是看起来很大,但这不是问题

以上是关于使用 PL/SQL 创建 XML的主要内容,如果未能解决你的问题,请参考以下文章

如何使用存储过程创建随机函数? PL/SQL

PL/SQL:使用编译错误创建的函数 [关闭]

使用自定义类型参数创建一个过程。 PL/SQL

如何使用输入参数创建 PL/SQL 存储过程以返回数据集

错误:无法在 PL/SQL 中使用选择创建过程

使用 PL/SQL 块创建触发器时出错