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.
- Validate JSON
- Read JSON
- 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…