Как к 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 шт):
Одно из решений, добавить элемент функцией 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>
Решение на чистом 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>