Как к XMLTYPE добавить дочерний элемент?

Надо к XMLTYPE добавить дочерний элемент, полученный из другого XMLTYPE.

Пробую с функцией APPENDCHILDXML:

declare
    xmlHead xmlType := xmlType ('
    <order>
      <head>
        <code>123</code>
        <date>2021-06-15</date>
      </head>
    </order>');
    xmlItem xmlType := xmlType ('
    <item>
      <itempos>456</itempos>
      <itemnam>item-name</itemnam>
    </item>');
    xmlOrder xmlType;
begin
    xmlOrder := appendChildXML (xmlHead, '//order', xmlItem);
end;

Но эта SQL функция не доступна в PL/SQL коде:

PLS-00201: identifier 'APPENDCHILDXML' must be declared

Ожидаемый результат:

<order>
  <head>
    <code>123</ord_code>
    <date>2021-06-15</date>
  </head>
  <item>
    <itempos>456<itempos>
    <itemnam>item-name</itemnam>
  </item>
</order>

Как можно добавить к xmlHead элемент xmlItem?


Ответы (2 шт):

Автор решения: Yitzhak Khabinsky

Одно из решений, добавить элемент функцией XMLQUERY.

Язык запросов и функциональный язык программирования XQuery (и выражение FLWOR) является предпочтительным решением для обработки XML по сравнению с проприетарными и устаревшими XML-функциями Oracle, такими как appendChildXML().

Воспроизводимый пример (на db<>fiddle):


DECLARE
   l_head_xml   XMLTYPE := XMLTYPE.CREATEXML('<order>
      <head>
        <code>123</code>
        <date>2021-06-15</date>
      </head>
    </order>');

   l_pos_xml   XMLTYPE := XMLTYPE.CREATEXML('<item>
      <itempos>456</itempos>
      <itemnam>item-name</itemnam>
    </item>');

   l_complete_xml  XMLTYPE;
BEGIN
   SELECT XMLQUERY('for $i in $h/order/head
                    return <order>
                           {$i}
                           {for $j in $p/item
                           return $j}
                           </order>'
                   PASSING l_head_xml AS "h",
                           l_pos_xml AS "p"
                   RETURNING CONTENT)
     INTO l_complete_xml
     FROM dual;

   dbms_output.put_line(l_complete_xml.getstringval());
END;
/

Результат:

<order>
    <head>
        <code>123</code>
        <date>2021-06-15</date>
    </head>
    <item>
        <itempos>456</itempos>
        <itemnam>item-name</itemnam>
    </item>
</order>
→ Ссылка
Автор решения: 0xdb

Решение на чистом PL/SQL - основано на API для XMLType (DBMS_XMLDOM).

Пример реализации (на db<>fiddle):

declare
    xmlOrder xmlType := xmlType ('
    <order>
      <head>
        <code>123</code>
        <date>2021-06-15</date>
      </head>
    </order>');
    xmlItem xmlType := xmlType ('
    <item>
      <itempos>456</itempos>
      <itemnam>item-name</itemnam>
    </item>');
    doc dbms_xmldom.domdocument := dbms_xmldom.newDOMDocument (xmldoc=>xmlOrder);
    itemdoc DBMS_XMLDOM.DOMDocument := dbms_xmldom.newDOMDocument (xmldoc=>xmlItem);
    ordernode dbms_xmldom.domnode;
    itemelem dbms_xmldom.DOMElement;
begin 
    itemelem := dbms_xmldom.makeElement(dbms_xmldom.importNode (doc, 
        dbms_xmldom.makeNode(dbms_xmldom.getDocumentElement(itemDoc)), true));
    ordernode := dbms_xmldom.item (dbms_xmldom.getElementsByTagName (doc, 'order'), 0);
    ordernode := dbms_xmldom.appendchild (ordernode, dbms_xmldom.makeNode(itemElem));
    
    dbms_output.put_line (dbms_xmldom.getXMLType (doc).getStringVal());
end;
/

Результат, как и ожидался:

<order>
  <head>
    <code>123</code>
    <date>2021-06-15</date>
  </head>
  <item>
    <itempos>456</itempos>
    <itemnam>item-name</itemnam>
  </item>
</order>
→ Ссылка