JSON format is getting used widely these days. You will eventually get a requirement to to interpret JSON data or create JSON data using SAP ABAP.

In this post, you will lean how to do this.

  1. Validate JSON
  2. Read JSON
  3. Create JSON

First, let us look at what is JSON data. You can visit json org to learn more about JSON. Here is a short version.

  • JSON – JavaScript Object Notation
  • It is a lightweight data-interchange format
  • It is easy for humans to read and write
  • It is easy for machines to parse and generate
  • It is based on a subset of the JavaScript Programming Language Standard
  • JSON is built on two structures:
    • A collection of name-value pairs
    • An ordered list of values

JSON Examples

The first example has a collection of name & value pairs. These pairs are name & Amar, age & 18, and city & Mumbai.

{
	"name": "Amar",
	"age": 18,
	"city": "Mumbai"
}

The second example below, shows the list of collections from first example. Each value in the JSON can either be direct value or list of name-value pairs / collections included in [ ] and separated by comma i.e. ‘,’.

{
	"students": [{
			"name": "Amar",
			"age": 18,
			"city": "Mumbai"
		},
		{
			"name": "Akbar",
			"age": 17,
			"city": "Mumbai"
		},
		{
			"name": "Anthony",
			"age": 16,
			"city": "Mumbai"
		}
	]
}

Sites such as https://jsonlint.com/ or https://jsonformatter.org/ can be used to validate the JSON data or format the JSON data for our testing.

JSON vs XML

JSON is vary similar to xml as both are human readable, both are hierarchical and both are used in various programming languages. But JSON is simpler than XML, it does not use end tags and hence shorter, simple to read & write.

Now, let us get back to how JSON can be handled in ABAP.

Validate Jason Data in ABAP

The class used to work with JSON in ABAP is cl_sxml_string_reader. As JSON and XMLs are similar – same class is used for both.

Code Sample

DATA : lv_string TYPE string VALUE '{"name": "Amar","age":18,"city": "Mumbai"}'.  
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 the JSON is valid, we get below output.

Then try invalid JSON by changing the JSON file to get below output.

DATA : lv_string TYPE string VALUE '{"name": "Amar","age":18,"city": "Mumbai"1}'.

Read JSON using ABAP

Reading JSON file with linear structure may not be a practical use case, but it will help in getting understanding of the code block.

TYPES :
  BEGIN OF ty_student,
    name TYPE string,
    age  TYPE i,
    city TYPE string,
  END OF ty_student.

DATA : lv_json    TYPE string VALUE '{"name": "Amar","age":18,"city": "Mumbai"}',
       lr_data    TYPE REF TO data,
       ls_student TYPE ty_student.

/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(<lfs_data>).

  DO 3 TIMES. "Number of fields

    CASE sy-index.
      WHEN 1. DATA(lv_fname) = 'NAME'.
      WHEN 2. lv_fname = 'AGE'.
      WHEN 3. lv_fname = 'CITY'.
    ENDCASE.

    ASSIGN COMPONENT sy-index OF STRUCTURE ls_student TO FIELD-SYMBOL(<lfs_field>).
    ASSIGN COMPONENT lv_fname OF STRUCTURE <lfs_data> TO FIELD-SYMBOL(<lfs_ref_value>).
    IF <lfs_ref_value> IS ASSIGNED AND <lfs_field> IS ASSIGNED.
      lr_data = <lfs_ref_value>.
      ASSIGN lr_data->* TO FIELD-SYMBOL(<lfs_actual_value>).
      IF <lfs_actual_value> IS ASSIGNED.
        <lfs_field> = <lfs_actual_value>.
      ENDIF.
    ENDIF.
  ENDDO.

  cl_demo_output=>display( ls_student ).

ENDIF.

When we know that we need the data as a table – we can use internal table instead of structure. We constantly need to move the data from data reference to field symbols to read the values.

TYPES :
  BEGIN OF ty_student,
    name TYPE string,
    age  TYPE i,
    city TYPE string,
  END OF ty_student.

DATA : lv_json    TYPE string,
       lr_data    TYPE REF TO data,
       ls_student TYPE ty_student,
       lt_student TYPE STANDARD TABLE OF ty_student.

FIELD-SYMBOLS : <lfs_table> TYPE ANY TABLE.


"Prepare JSON string for testing

lv_json = '{"students": [{"name": "Amar","age": 18,"city": "Mumbai"},' &&
          '{"name": "Akbar","age": 17,"city": "Mumbai"},' &&
          '{"name": "Anthony","age": 16,"city": "Mumbai"} ] }'.

/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(<lfs_data>).
  ASSIGN COMPONENT 'STUDENTS' OF STRUCTURE <lfs_data> TO FIELD-SYMBOL(<lfs_results>).
  ASSIGN <lfs_results>->* TO <lfs_table>.

  LOOP AT <lfs_table> ASSIGNING FIELD-SYMBOL(<lfs_row>).

    DO 3 TIMES. "Number of fields

      CASE sy-index.
        WHEN 1. DATA(lv_fname) = 'NAME'.
        WHEN 2. lv_fname = 'AGE'.
        WHEN 3. lv_fname = 'CITY'.
      ENDCASE.

      ASSIGN COMPONENT sy-index OF STRUCTURE ls_student TO FIELD-SYMBOL(<lfs_field>).

      ASSIGN <lfs_row>->* TO FIELD-SYMBOL(<lfs_row_val>).
      ASSIGN COMPONENT lv_fname OF STRUCTURE <lfs_row_val> TO FIELD-SYMBOL(<lfs_ref_value>).
      IF <lfs_ref_value> IS ASSIGNED AND <lfs_field> IS ASSIGNED.
        ASSIGN <lfs_ref_value>->* TO FIELD-SYMBOL(<lfs_actual_value>).
        IF <lfs_actual_value> IS ASSIGNED.
          <lfs_field> = <lfs_actual_value>.
        ENDIF.
      ENDIF.
    ENDDO.

    APPEND ls_student TO lt_student.

  ENDLOOP.

  cl_demo_output=>display( lt_student ).

ENDIF.

Is this the best solution? Probably not – but its enough to get started in building one.

Create JSON using 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 ) ).

There are more options available as well.

CALL TRANSFORMATION

In example above we used transformation to display the json as HTML. Here, we will use it as itab to JSON transformation.

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 appears like below in debug mode.

The same json string can then be used to test the reverse transformation.

CLEAR lt_scarr.
CALL TRANSFORMATION id
  SOURCE XML lv_json
  RESULT values = lt_scarr.

cl_demo_output=>display( lt_scarr ).

The next step in this journey is to study class CL_SXML_TABLE_READER and how it can be used to get specific data. SAP has created sample programs in package SXML_DEMO and programs starting with DEMO_JASON_*

Visit ABAP Code Samples page for more code samples.


If you like the content, please subscribe…

Join 2,647 other followers