Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, M. Ogun.

Asked: January 09, 2020 - 1:52 pm UTC

Last updated: January 10, 2020 - 9:44 am UTC

Version: 19

Viewed 1000+ times

You Asked

Hi,

I am trying to parse an xml response that has multiple child nodes.

It's something like:

<List>
  <Status>ACK</Status>
  <Status>ACK</Status>
  <Status>NACK</Status>
</List>


I was able to extract one line at a time. But I need to get all of them at once and store in apex_collections.

So I tried these (possibly not-so-wise) things:

- declare the xpath with an anchor
l_xpath_anchor varchar2(100) := '//List[~]/Status/text()';


- create a loop and replace ~ with consecutive numbers, starting from 1 obviously. Then in the same loop call the parse_xml API:

select apex_web_service.parse_xml_clob(
                         p_xml => env,
    p_xpath => l_xpath_anchor,
    p_ns => l_xmlns)
into l_foo
from (select xmltype(service_response) env from xml_master where tx_id = 202001071406422305841 and tx_uid = 413);
l_xpath := replace(l_xpath, '~', i);
dbms_output.put_line (l_foo||'  i: '||i);


This actually worked for a sample data like above. It has 3 child nodes and I knew it had to loop 3 times.
But I can never it on original data.

Is there a way to know how many child node does a parent node have so I can be sure about how many time should it loop?

and Chris said...

If you're trying to pull out all the Status values, passing the document to XMLTable seems a better way to me.

With this you can convert the XML to relational rows-and-columns:

with x as (
  select xmltype ( '<List>
  <Status>ACK</Status>
  <Status>ACK</Status>
  <Status>NACK</Status>
</List>' ) doc
  from  dual
)
  select xt.* from x, xmltable (
    '/List/Status'
    passing x.doc 
    columns  
      status varchar2(10) path '//text()'
  ) xt;

STATUS   
ACK       
ACK       
NACK    

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

swift response

Ogun, January 10, 2020 - 7:52 am UTC

Hi,

Thank you very much.

While I was waiting for an answer, I kept trying some other things.

I am not sure if this is a smart approach but I tried to catch
"/>" 
and count it by using
regexp_count 
against the xml response of my envelope. Then I created my loop for that number.

Would you say it's a bad idea? Should I stick with
xmltable()
?

Thank you again,

Have a great weekend.
Chris Saxon
January 10, 2020 - 9:44 am UTC

I'm not clear exactly what you're doing after extracting the values. But as a general principle for data processing:

Loops => SLOW
One SQL statement => FAST

So I'd lean towards using XMLTable to get the data you want. But really it depends on what you're doing next with these values.

I tried to catch "/>"

Sounds risky to me. What the response changes to include extra attributes? You'll be looping more than needed.

More to Explore

SQL

The Oracle documentation contains a complete SQL reference.