Nianios
Nianios

Reputation: 1436

Check XMLType node value and update if necessary

I have a simle xml like this:

<Parameters>
 <Parameter>
  <Index>0</Index>
  <Name>Date</Name>
  <Value>@Today</Value>
 </Parameter>
 <Parameter>
  <Index>1</Index>
  <Name>Id</Name>
  <Value>22</Value>
 </Parameter>
</Parameters>

I would like to iterate through each parameter and if the value starts with '@' called a function that takes as parameter the value and returns a new value.
Use the newvalue to update the xml.
I 've found how to use the updatexml, but no luck how to implement my scenario.

Upvotes: 2

Views: 226

Answers (2)

Mathias Magnusson
Mathias Magnusson

Reputation: 197

How about this? If using in PL*SQL, just use only the function.

  select updatexml(xmltype('<Parameters>
         <Parameter>
          <Index>0</Index>
          <Name>Date</Name>
          <Value>@Today</Value>
         </Parameter>
         <Parameter>
          <Index>1</Index>
          <Name>Id</Name>
          <Value>22</Value>
         </Parameter>
        </Parameters>'), '/Parameters/Parameter/Value[text()="@Today"]', to_char(sysdate, 'dd/mm/yyyy')) 
from dual;

Note that it is a function I call, replace with your own if desiered.

For many different variants, just add one such change after another in the upatexml such as:

  select updatexml(xmltype('<Parameters>
         <Parameter>
          <Index>0</Index>
          <Name>Date</Name>
          <Value>@Today</Value>
         </Parameter>
         <Parameter>
          <Index>1</Index>
          <Name>Id</Name>
          <Value>22</Value>
         </Parameter>
         <Parameter>
          <Index>2</Index>
          <Name>Id</Name>
          <Value>@Yesterday</Value>
         </Parameter>
        </Parameters>'), '/Parameters/Parameter/Value[text()="@Today"]/text()'    , to_char(sysdate    , 'dd/mm/yyyy')
                       , '/Parameters/Parameter/Value[text()="@Yesterday"]/text()', to_char(sysdate - 1, 'dd/mm/yyyy')) 
from dual;

Upvotes: 1

Stawros
Stawros

Reputation: 935

You can do it in cycle by each parameter node, changing value by function (inner CheckXmlValue in my code) -

declare
  cur_xml  sys_refcursor;
  v_val varchar2(3000);
  n_val varchar2(3000);
  xml_     XMLType := XMLType(
        '<Parameters>
         <Parameter>
          <Index>0</Index>
          <Name>Date</Name>
          <Value>@Today</Value>
         </Parameter>
         <Parameter>
          <Index>1</Index>
          <Name>Id</Name>
          <Value>22</Value>
         </Parameter>
        </Parameters>'
);
    function CheckXmlValue(val_ in varchar2) return varchar2 is
    begin
        return 
            case lower(val_)
                when '@today' then to_char(sysdate, 'dd/mm/yyyy')
                when '@yesterday' then to_char(sysdate-1, 'dd/mm/yyyy')
                else val_
            end;
    end;
begin
  open cur_xml for
    select extractValue(column_value, '//Value') str
      from table(XMLSequence(extract(xml_, '/Parameters/Parameter')));
  loop
    fetch cur_xml into v_val;
    n_val := CheckXmlValue(v_val);
    exit when cur_xml%notfound;
    select updateXml (
                xml_,
                '//Parameters/Parameter/Value[text()="'||v_val||'"]/text()',
                n_val
           )
    into xml_
    from DUAL;
  end loop;
  close cur_xml;
  -- result:
  dbms_output.put_line(xml_.extract('*').getStringVal());
end;
/

Upvotes: 4

Related Questions