rplantiko
rplantiko

Reputation: 2738

Convert ABAP data into an iXML object representing them in JSON-XML format

I want to read arbitrary ABAP data into an iXML document object which contains the JSON-XML representation of these data.

The only way I see is a double application of the id transformation which is not very efficient:

data(lo_aux1) = cl_sxml_string_writer=>create( if_sxml=>co_xt_json ).
call transformation id
  source data = ls_some_abap_data
  result xml lo_aux1.
data(lv_aux2) = lo_aux1->get_output( ).
data(lo_result) = cl_ixml=>create( )->create_document( ).
call transformation id
  source xml lv_aux2
  result xml lo_result. 

Now lo_result is an iXML DOM representation of the ABAP data in the JSON-XML format, as required. Is it possible to obtain it in a more direct way?

Note: I am not interested in result objects of the sXML family, as I want to manipulate / extend the resulting JSON-XML document with the usual XML DOM methods, which is impossible for an sXML writer object (sXML writers are so simple they can only write everything they have into an output object, but don't allow editing of parts of the object that they already contain).

Upvotes: 2

Views: 1424

Answers (1)

Suncatcher
Suncatcher

Reputation: 10621

I am sitting at a proxy and want to enrich the incoming JSON payload by some ABAP data, before passing it to the endpoint. Strategy: parse the incoming JSON into an JSON-XML doc, read the (complex) ABAP data into a second XML doc, then add XML subtrees of the second to the first before finally producing the result JSON from the first JSON-XML doc

I don't understand the need of iXML at all here. Converting complex ABAP structure into XML to merge it with JSON is redundant here. Let's assume you received some JSON data from Web-Service:

{  
   "main":{  
      "PASSENGERS":[  
         {  
            "NAME":"Horst",
            "TITLE":"Herr",
            "AGE":30
         },
         {  
            "NAME":"Jutta",
            "TITLE":"Frau",
            "AGE":35
         },
         {  
            "NAME":"Ingo",
            "TITLE":"Herr",
            "AGE":31
         }
      ]
   }
}

And you want enrich each passenger data with flight data from SFLIGHT table. You can manipulate the nodes and attributes with cl_sxml_string_writer just like this:

DATA(lv_json) = CONV string( '{"main": {"PASSENGERS":[ {"NAME":"Horst","TITLE":"Herr","AGE":30}, {"NAME":"Jutta","TITLE":"Frau","AGE":35}, {"NAME":"Ingo","TITLE":"Herr","AGE":31} ]}}' ).

DATA open_element TYPE REF TO if_sxml_open_element.
DATA value TYPE REF TO if_sxml_value_node.

DATA(o_json) = cl_abap_codepage=>convert_to( lv_json ).
DATA(reader) = cl_sxml_string_reader=>create( o_json ).

SELECT DISTINCT connid, fldate, planetype FROM sflight INTO TABLE @DATA(lt_flight).

DATA(xml) = cl_abap_codepage=>convert_to( lv_json ).

DATA(out) = cl_demo_output=>new( )->begin_section( 'Original JSON' )->write_xml( xml ).

DATA(writer) = CAST if_sxml_writer( cl_sxml_string_writer=>create( ) ).
open_element = writer->new_open_element( name = 'flights' nsuri = reader->nsuri ).
writer->write_node( open_element ).
DATA(i) = 1.
DO.
  DATA(node) = reader->read_next_node( ).
  IF node IS INITIAL.
    EXIT.
  ENDIF.
  IF node IS INSTANCE OF if_sxml_value_node.
    DATA(value_node) = CAST if_sxml_value_node( node ).
    value_node->set_value( to_upper( value_node->get_value( ) ) ).
  ENDIF.
  writer->write_node( node ).
  IF node->type = if_sxml_node=>co_nt_element_open.
    DATA(op) = CAST if_sxml_open_element( node ).
    CHECK op->qname-name = 'object' AND op->get_attributes( ) IS INITIAL.
    open_element = writer->new_open_element( name = 'flight' nsuri = reader->nsuri ).
    open_element->set_attribute( name = 'FLIGHT_DATE'
                                 value = | { lt_flight[ i ]-fldate } | ).
    open_element->set_attribute( name = 'PLANE_TYPE'
                                 value = | { lt_flight[ i ]-planetype } | ).
    writer->write_node( open_element ).
    value = writer->new_value( ).
    value->set_value( | { lt_flight[ i ]-connid } | ).
    writer->write_node( value ).
    writer->write_node( writer->new_close_element( ) ).
    i = i + 1.
  ENDIF.
ENDDO.
writer->write_node( writer->new_close_element( ) ).
out->next_section( 'Modified JSON'
  )->write_xml(
    CAST cl_sxml_string_writer( writer )->get_output( )
  )->display( ).

DATA(result_json) = CAST cl_sxml_string_writer( writer )->get_output(  ).

Resulted JSON will be dumped into result_json variable and you can push it further wherever you want.

Here is resulted JSON, with capitalized passenger values and extended with flight node, which contains flight number and attributed with data and plane type:

<flights>
 <object>
  <flight FLIGHT_DATE=" 20160610 " PLANE_TYPE=" A380‑800 "> 0002 </flight>
  <object name="main">
   <array name="PASSENGERS">
    <object>
     <flight FLIGHT_DATE=" 20160712 " PLANE_TYPE=" A380‑800 "> 0002 </flight>
     <str name="NAME">HORST</str>
     <str name="TITLE">HERR</str>
     <num name="AGE">30</num>
    </object>
    <object>
     <flight FLIGHT_DATE=" 20160813 " PLANE_TYPE=" A380‑800 "> 0002 </flight>
     <str name="NAME">JUTTA</str>
     <str name="TITLE">FRAU</str>
     <num name="AGE">35</num>
    </object>
    <object>
     <flight FLIGHT_DATE=" 20160914 " PLANE_TYPE=" A380‑800 "> 0002 </flight>
     <str name="NAME">INGO</str>
     <str name="TITLE">HERR</str>
     <num name="AGE">31</num>
    </object>
   </array>
  </object>
 </object>
</flights> 

Upvotes: 1

Related Questions