ABAP and JSON

JSON format is widely used these days. While developing using SAP ABAP, we may need to interpret, read or create JSON formatted data. In this blog post, I will try to explain how we can do the operations we need.

 ABAP and JSON

To give some information about JSON (JavaScript Object Notation) before starting to use ABAP:

  • It is based on a subset of the JavaScript programming language standard.
  • It is easy for programmers to read and write.
  • It is easy for machines to parse and create.
  • It is based on two structures:
    • A collection of name-value pairs
    • An ordered list of values

JSON Examples

The first example has a collection of name and value pairs. These pairs are shown in the following structure, which includes material (matnr), material definition (maktx), basic unit of measurement (meins) and values.

 {   "matnr": "50065557",   "maktx": "Test Malzeme",   "meins": "ST" } 

The second example below shows the list of collections in the first example.

 {   "materials": [     {       "matnr": "50065557",       "maktx": "Test Malzeme",       "meins": "ST"     },     {       "matnr": "50065558",       "maktx": "Test Malzeme2",       "meins": "ST"     },     {       "matnr": "50065559",       "maktx": "Test Malzeme3",       "meins": "ST"     }   ] } 

JSON ve XML

JSON works similarly to XML. Both are programmer readable, both are hierarchical and used in various programming languages. However, JSON is simpler than XML, does not use tags and is therefore shorter and easier to read and write.

Now let's go back to how JSON can be processed in ABAP.

Validating JSON Data in ABAP

We will check the accuracy of the data using the CL_SXML_STRING_READER class. As I mentioned above, JSON and XML are similar, so the same class can be used for both.

 DATA lv_json TYPE string VALUE '{"matnr":"50065557","maktx":"Test Malzeme","meins":"ST"}'.  DATA(lo_reader) = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( lv_json ) ).  TRY.     lo_reader->next_node( ).     lo_reader->skip_node( ).     cl_demo_output=>display( 'JSON is valid' ).   CATCH cx_sxml_parse_error INTO DATA(lx_parse_error).     cl_demo_output=>display( lx_parse_error->get_text( ) ). ENDTRY. 

When JSON is valid, we output "JSON is valid".

Next, let's change our JSON string to get an error and try again.

 DATA lv_json TYPE string VALUE '{"matnr":"50065557","maktx":"Test Malzeme","meins":"ST"ASL}'.  DATA(lo_reader) = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( lv_json ) ).  TRY.     lo_reader->next_node( ).     lo_reader->skip_node( ).     cl_demo_output=>display( 'JSON is valid' ).   CATCH cx_sxml_parse_error INTO DATA(lx_parse_error).     cl_demo_output=>display( lx_parse_error->get_text( ) ). ENDTRY. 

When we execute the program, “Error while parsing an XML stream: '',' or '}' expected at 'ASL}''.” We get the output.

Reading JSON Data in ABAP

We will read and parse the data using the /UI2/CL_JSON class. We have different alternatives to do this, but it is a good option for a start.

 TYPES:   BEGIN OF ty_material,     matnr TYPE string,     maktx TYPE string,     meins TYPE string,   END OF ty_material.  DATA:   lv_json     TYPE string,   lr_data     TYPE REF TO data,   ls_material TYPE ty_material,   lt_material TYPE STANDARD TABLE OF ty_material.  FIELD-SYMBOLS  TYPE ANY TABLE.  lv_json = '{"materials": [{"matnr":"50065557","maktx":"Test Malzeme","meins":"ST"},' &&                          '{"matnr":"50065558","maktx":"Test Malzeme2","meins":"ST"},' &&                          '{"matnr":"50065559","maktx":"Test Malzeme3","meins":"ST"} ] } '.  /ui2/cl_json=>deserialize(   EXPORTING     json         = lv_json     pretty_name  = /ui2/cl_json=>pretty_mode-user     assoc_arrays = abap_true   CHANGING     data         = lr_data ).  IF lr_data IS BOUND.   ASSIGN lr_data->* TO FIELD-SYMBOL().   ASSIGN COMPONENT 'MATERIALS' OF STRUCTURE  TO FIELD-SYMBOL().   ASSIGN ->* TO .   LOOP AT  ASSIGNING FIELD-SYMBOL().     DO 3 TIMES.       CASE sy-index.         WHEN 1.           DATA(lv_fname) = 'MATNR'.         WHEN 2.           lv_fname = 'MAKTX'.         WHEN 3.           lv_fname = 'MEINS'.       ENDCASE.        ASSIGN COMPONENT sy-index OF STRUCTURE ls_material TO FIELD-SYMBOL().       ASSIGN ->* TO FIELD-SYMBOL().       ASSIGN COMPONENT lv_fname OF STRUCTURE  TO FIELD-SYMBOL().       IF  IS ASSIGNED AND  IS ASSIGNED.         ASSIGN ->* TO FIELD-SYMBOL().         IF  IS ASSIGNED.            = .         ENDIF.       ENDIF.     ENDDO.     APPEND ls_material TO lt_material.   ENDLOOP.   cl_demo_output=>display( lt_material ). ENDIF. 

When we run the program, the output will be as follows.

Generating JSON Data in ABAP

 SELECT * FROM scarr INTO TABLE @DATA(lt_scarr).  DATA(lv_json) = /ui2/cl_json=>serialize(   data        = lt_scarr   compress    = abap_true   pretty_name = /ui2/cl_json=>pretty_mode-camel_case ).  " Display JSON in ABAP CALL TRANSFORMATION sjson2html SOURCE XML lv_json                            RESULT XML DATA(lvc_html). cl_abap_browser=>show_html(   title       = 'Sample JSON'   html_string = cl_abap_codepage=>convert_from( lvc_html ) ). 

The output of the program will be as follows.

In the above example, we used CALL TRANSFORMATION to display JSON as HTML. Here we will use it as internal table -> JSON conversion.

 DATA lv_json TYPE string. SELECT * FROM scarr INTO TABLE @DATA(lt_scarr).  DATA(lo_writer) =   cl_sxml_string_writer=>create(   type = if_sxml=>co_xt_json ).  CALL TRANSFORMATION id   SOURCE values = lt_scarr   RESULT XML lo_writer.  cl_abap_conv_in_ce=>create( )->convert(   EXPORTING     input = lo_writer->get_output( )   IMPORTING     data = lv_json ). 

The JSON string looks like below in debug.

We can still convert the string we created via CALL TRANSFORMATION.

 CLEAR lt_scarr. CALL TRANSFORMATION id   SOURCE XML lv_json   RESULT values = lt_scarr.  cl_demo_output=>display( lt_scarr ). 

The output of the program will be as follows.

You can search for the CL_SXML_TABLE_READER class and how to use it to get more information. You can also examine demo programs starting with DEMO_JSON_* in the SABAPDEMOS package.