Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Very trusting JSON to (deep) ABAP data structure mapper
*&---------------------------------------------------------------------*
*& Form json_to_data
*&---------------------------------------------------------------------*
form json_to_data using json type string changing data type any.
data: lv_off type i.
data: lv_len type i.
data: lv_key type string.
data: lv_value type string.
data: lv_char type char1. "Current chacater
data: lv_pchar type char1. "Previous character
data: lv_instr type boole_d. "Indicator: cursor in string
data: lv_level type i. "Depth inside a block
data: lv_table type boole_d.
field-symbols: <fk> type string.
field-symbols: <data> type any.
field-symbols: <table> type any table.
field-symbols: <sotab> type sorted table.
field-symbols: <sttab> type standard table.
field-symbols: <line> type any.
data: ls_line type ref to data.
data: lr_td type ref to cl_abap_typedescr.
data: lr_ttd type ref to cl_abap_tabledescr.
* If the incoming json contains no '{}[]', we are dealing with
* a basic (scalar) value that is simply assigned to the data
* and then we return
if json na '{}[]'.
* Replace escape characters (TODO: Check if there are more!)
lv_value = json.
replace all occurrences of '\n' in lv_value with cl_abap_char_utilities=>newline.
replace all occurrences of '\t' in lv_value with cl_abap_char_utilities=>horizontal_tab.
replace all occurrences of '\f' in lv_value with cl_abap_char_utilities=>form_feed.
replace all occurrences of '\v' in lv_value with cl_abap_char_utilities=>vertical_tab.
replace all occurrences of '\b' in lv_value with cl_abap_char_utilities=>backspace.
replace all occurrences of '\\' in lv_value with '\'.
* TODO: Deal with specific data types, e.g. dates etc.
data = lv_value.
exit.
endif.
lv_len = strlen( json ).
* Check if we are dealing with a table
lr_td = cl_abap_typedescr=>describe_by_data( data ).
if lr_td->type_kind = cl_abap_typedescr=>typekind_table.
* This information is used later...
lv_table = 'X'.
assign data to <table>.
create data ls_line like line of <table>.
assign ls_line->* to <line>.
else.
lv_table = ' '.
endif.
* Reset counters/flags
lv_off = 0.
lv_instr = ' '.
lv_level = 0.
assign lv_key to <fk>.
while lv_off < lv_len.
lv_char = json+lv_off(1).
**********************************************************************
* IN STRING
**********************************************************************
* Character is in a string delimited by double quotes
if lv_instr = 'X'.
if lv_char = '"'.
* Switch out of delimited character string
if lv_pchar ne '\'.
lv_instr = ' '.
else.
concatenate <fk> lv_char into <fk> respecting blanks.
endif.
else.
concatenate <fk> lv_char into <fk> respecting blanks.
endif.
**********************************************************************
* OUTSIDE STRING
**********************************************************************
* Character is not in a string delimited by double quotes
else.
* On opening character, shift level up
if lv_char ca '{['.
add 1 to lv_level.
endif.
* When the value is contained in a {}/[], the entire value must
* be passed to the next level of processing
if lv_level > 1.
concatenate <fk> lv_char into <fk> respecting blanks.
else.
if lv_char ca '[{'. "<- Chars ignored outside of str
elseif lv_char = ':'.
assign lv_value to <fk>.
* The key collected up to now is assigned to the data member
translate lv_key to upper case.
shift lv_key left deleting leading space.
assign component lv_key of structure data to <data>.
* End of a key/value pair (we bump up against delimiter) - pass to next level
elseif ( lv_char = ',' or lv_char = '}' ) and lv_table = space.
* Process collected value
shift lv_value left deleting leading space.
perform json_to_data using lv_value changing <data>.
* Clear key and value
clear: lv_key, lv_value.
assign lv_key to <fk>.
clear: lv_key, lv_value.
* End of a key/value pair (we bump up against delimiter) - pass to next level
* But in table mode, we pass an instance of a row of the table, and afterward
* add it to the table
elseif ( lv_char = ',' or lv_char = ']' ) and lv_table = 'X'.
* Process collected value
* Inside array in JSON, there are no keys, only list of values, the collected
* value is in lv_key
shift lv_key left deleting leading space.
perform json_to_data using lv_key changing <line>.
* On return: if dealing with table, add the record to the table
lr_ttd ?= lr_td.
if lr_ttd->table_kind = cl_abap_tabledescr=>tablekind_sorted
or lr_ttd->table_kind = cl_abap_tabledescr=>tablekind_hashed.
assign data to <sotab>.
insert <line> into table <sotab>.
else.
assign data to <sttab>.
append <line> to <sttab>.
endif.
clear <line>.
* Clear key and value
clear: lv_key, lv_value.
assign lv_key to <fk>.
clear: lv_key, lv_value.
* Switch cursor into delimited string; consecutive characters
* are then treated as part of a key or value, even if they are
* special characters
elseif lv_char = '"'.
lv_instr = 'X'.
* Other chars processed as either key or value
else.
concatenate <fk> lv_char into <fk> respecting blanks.
endif.
endif.
* On closing character, shift level down again
if lv_char ca '}]'.
subtract 1 from lv_level.
endif.
* END: Are we in string or out?
endif.
lv_pchar = lv_char.
add 1 to lv_off.
endwhile.
endform. "json_to_data
@SP513582

This comment has been minimized.

Copy link

@SP513582 SP513582 commented Feb 21, 2014

Hello, how to hand with as normal Json-File. It doesn't work in this case.

{
"results" : [
{
"address_components" : [
{
"long_name" : "Subotica",
"short_name" : "SU",
"types" : [ "locality", "political" ]
},
{
"long_name" : "North Bačka District",
"short_name" : "North Bačka District",
"types" : [ "administrative_area_level_2", "political" ]
},
{
"long_name" : "Vojvodina",
"short_name" : "Vojvodina",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "Serbia",
"short_name" : "RS",
"types" : [ "country", "political" ]
}
],
"formatted_address" : "Subotica, Serbia",
"geometry" : {
"bounds" : {
"northeast" : {
"lat" : 46.1897987,
"lng" : 19.7770429
},
"southwest" : {
"lat" : 45.9975281,
"lng" : 19.5711994
}
},
"location" : {
"lat" : 46.098209,
"lng" : 19.67111
},
"location_type" : "APPROXIMATE",
"viewport" : {
"northeast" : {
"lat" : 46.1897987,
"lng" : 19.7770429
},
"southwest" : {
"lat" : 45.9975281,
"lng" : 19.5711994
}
}
},
"types" : [ "locality", "political" ]
}
],
"status" : "OK"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment