2

I have created the following test case to demonstrate my issue:

create table test_table (idx number, a varchar2(20), b varchar2(20));
insert into test_table values (1, 'item1', 'value1');
insert into test_table values (2, 'item2', 'value2');

select appendChildXML(
                        xmltype('<inventory></inventory>'),
                        '/inventory', 
                        xmlagg(
                          xmlelement("id", xmlattributes(tt.idx as "val"),
                            xmlelement("listing",
                              xmlelement("item",tt.a),
                              xmlelement("value",tt.b)
                        )))) as xml
from test_table tt
;

This gives the desired output of:

<inventory>  
  <id val="1">  
    <listing>
      <item>item1</item>  
      <value>value1</value>  
    </listing>  
  </id>  
  <id val="2">  
    <listing>  
      <item>item2</item>  
      <value>value2</value>  
    </listing>  
  </id>  
</inventory>

However, if I try to use XMLQuery I get an error.

select XMLQuery(
                  (
                    'copy $tmp := . modify insert node '
                    || xmlagg(
                          xmlelement("id", xmlattributes(tt.idx as "val"),
                            xmlelement("listing",
                              xmlelement("item",tt.a),
                              xmlelement("value",tt.b)
                       )))
                    || ' as last into $tmp/inventory return $tmp'
                  )
                  PASSING xmltype('<inventory></inventory>') RETURNING CONTENT
                ) as xml
from test_table tt
;

Error:

ORA-19112: error raised during evaluation: 
XVM-01003: [XPST0003] Syntax error at 'id'
1   copy $tmp := . modify insert node <id val="1"><listing><item>item1</item><v
-                                                                                                                ^

19112. 00000 -  "error raised during evaluation: %s"
*Cause:    The error function was called during evaluation of the XQuery expression.
*Action:   Check the detailed error message for the possible causes.

I believe the problem has to do with the fact that I'm inserting multiple id nodes as it will work if I only have one in the table, but I don't understand why appendChildXML will work and XMLQuery will not.

I'm guessing maybe I need to use a FLWOR expression, but I haven't been able to create one that works.

I am currently using Oracle 11g and will be moving to 12c (trying to move to XMLQuery since appendChildXML is deprecated in 12c). I have little experience with XML in Oracle and no previous XMLQuery experience.

Can anyone offer advice on how to get the XMLQuery to work? Thanks!

DBox
  • 49
  • 1
  • 7

2 Answers2

1

You can use the ora:view function to query the table and then generate the XML with the FLWOR expression, something like this:

10/12/2015 19:53:25:SQL> SELECT XMLQuery('<inventory>
  2                   {for $i in ora:view("TEST_TABLE")
  3                     let $idval := $i/ROW/IDX,
  4                         $item  := $i/ROW/A/text(),
  5                         $value := $i/ROW/B/text()
  6                     return <id val="{$idval}">
  7                               <listing>
  8                                 <item>{$item}</item>
  9                                 <value>{$value}</value>
 10                               </listing>
 11                             </id>}
 12                   </inventory>'
 13                  RETURNING CONTENT) AS test_xml
 14    FROM DUAL;

TEST_XML
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
<inventory><id val="1"><listing><item>item1</item><value>value1</value></listing></id><id val="2"><listing><item>item2</item><value>value2</value></listing></id></inventory>
Francisco Sitja
  • 963
  • 4
  • 7
  • Where would the existing inventory node be located (file, table, variable)? How can we obtain it to "merge" with the new ID subnodes? – Francisco Sitja Dec 11 '15 at 17:23
  • The existing inventory node would be located in a table in the actual implementation and this will be used in an update statement. I was able to mimic that in the test select statement by just giving it a blank inventory node. Thanks again! – DBox Dec 15 '15 at 14:25
0

I was able to get the results I needed via the query below. Thanks to Francisco Sitja for his answer and FLWOR expression that guided me toward the complete answer.

select XMLQuery(
                  (
                    'copy $tmp := . modify insert node '
                    || 'for $i in ora:view("TEST_TABLE")
                          let $idval := $i/ROW/IDX,
                              $item  := $i/ROW/A/text(),
                              $value := $i/ROW/B/text()
                         return <id val="{$idval}">
                                  <listing>
                                    <item>{$item}</item>
                                    <value>{$value}</value>
                                  </listing>
                                </id>'
                    || ' as last into $tmp/inventory return $tmp'
                  )
                  PASSING xmltype('<inventory></inventory>') RETURNING CONTENT
                ) as xml
from dual;
DBox
  • 49
  • 1
  • 7