abapGit/src/json/zcl_abapgit_ajson.clas.abap
github-actions[bot] b028446d57
ajson, Automatic Update (#4922)
* [create-pull-request] automated change

* Update zcl_abapgit_ajson.clas.testclasses.abap

* Update zcl_abapgit_ajson.clas.testclasses.abap

* skip unit test parse_error

Co-authored-by: larshp <larshp@users.noreply.github.com>
Co-authored-by: Lars Hvam <larshp@hotmail.com>
2021-08-30 07:35:00 +02:00

775 lines
21 KiB
ABAP

CLASS zcl_abapgit_ajson DEFINITION
PUBLIC
CREATE PRIVATE .
PUBLIC SECTION.
INTERFACES zif_abapgit_ajson .
ALIASES:
exists FOR zif_abapgit_ajson~exists,
members FOR zif_abapgit_ajson~members,
get FOR zif_abapgit_ajson~get,
get_boolean FOR zif_abapgit_ajson~get_boolean,
get_integer FOR zif_abapgit_ajson~get_integer,
get_number FOR zif_abapgit_ajson~get_number,
get_date FOR zif_abapgit_ajson~get_date,
get_timestamp FOR zif_abapgit_ajson~get_timestamp,
get_string FOR zif_abapgit_ajson~get_string,
slice FOR zif_abapgit_ajson~slice,
to_abap FOR zif_abapgit_ajson~to_abap,
array_to_string_table FOR zif_abapgit_ajson~array_to_string_table.
ALIASES:
clear FOR zif_abapgit_ajson~clear,
set FOR zif_abapgit_ajson~set,
set_boolean FOR zif_abapgit_ajson~set_boolean,
set_string FOR zif_abapgit_ajson~set_string,
set_integer FOR zif_abapgit_ajson~set_integer,
set_date FOR zif_abapgit_ajson~set_date,
set_timestamp FOR zif_abapgit_ajson~set_timestamp,
set_null FOR zif_abapgit_ajson~set_null,
delete FOR zif_abapgit_ajson~delete,
touch_array FOR zif_abapgit_ajson~touch_array,
push FOR zif_abapgit_ajson~push,
stringify FOR zif_abapgit_ajson~stringify.
ALIASES:
mt_json_tree FOR zif_abapgit_ajson~mt_json_tree,
keep_item_order FOR zif_abapgit_ajson~keep_item_order,
freeze FOR zif_abapgit_ajson~freeze.
CLASS-METHODS parse
IMPORTING
!iv_json TYPE string
!iv_freeze TYPE abap_bool DEFAULT abap_false
!ii_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
RETURNING
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson
RAISING
zcx_abapgit_ajson_error .
CLASS-METHODS create_empty
IMPORTING
!ii_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping OPTIONAL
RETURNING
VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson.
PROTECTED SECTION.
PRIVATE SECTION.
TYPES:
tty_node_stack TYPE STANDARD TABLE OF REF TO zif_abapgit_ajson=>ty_node WITH DEFAULT KEY.
DATA mv_read_only TYPE abap_bool.
DATA mi_custom_mapping TYPE REF TO zif_abapgit_ajson_mapping.
DATA mv_keep_item_order TYPE abap_bool.
METHODS get_item
IMPORTING
iv_path TYPE string
RETURNING
VALUE(rv_item) TYPE REF TO zif_abapgit_ajson=>ty_node.
METHODS prove_path_exists
IMPORTING
iv_path TYPE string
RETURNING
VALUE(rt_node_stack) TYPE tty_node_stack
RAISING
zcx_abapgit_ajson_error.
METHODS delete_subtree
IMPORTING
iv_path TYPE string
iv_name TYPE string
RETURNING
VALUE(rv_deleted) TYPE abap_bool.
ENDCLASS.
CLASS zcl_abapgit_ajson IMPLEMENTATION.
METHOD create_empty.
CREATE OBJECT ro_instance.
ro_instance->mi_custom_mapping = ii_custom_mapping.
ENDMETHOD.
METHOD delete_subtree.
DATA lv_parent_path TYPE string.
DATA lv_parent_path_len TYPE i.
FIELD-SYMBOLS <node> LIKE LINE OF mt_json_tree.
READ TABLE mt_json_tree ASSIGNING <node>
WITH KEY
path = iv_path
name = iv_name.
IF sy-subrc = 0. " Found ? delete !
IF <node>-children > 0. " only for objects and arrays
lv_parent_path = iv_path && iv_name && '/'.
lv_parent_path_len = strlen( lv_parent_path ).
LOOP AT mt_json_tree ASSIGNING <node>.
IF strlen( <node>-path ) >= lv_parent_path_len
AND substring( val = <node>-path
len = lv_parent_path_len ) = lv_parent_path.
DELETE mt_json_tree INDEX sy-tabix.
ENDIF.
ENDLOOP.
ENDIF.
DELETE mt_json_tree WHERE path = iv_path AND name = iv_name.
rv_deleted = abap_true.
DATA ls_path TYPE zif_abapgit_ajson=>ty_path_name.
ls_path = lcl_utils=>split_path( iv_path ).
READ TABLE mt_json_tree ASSIGNING <node>
WITH KEY
path = ls_path-path
name = ls_path-name.
IF sy-subrc = 0.
<node>-children = <node>-children - 1.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD get_item.
FIELD-SYMBOLS <item> LIKE LINE OF mt_json_tree.
DATA ls_path_name TYPE zif_abapgit_ajson=>ty_path_name.
ls_path_name = lcl_utils=>split_path( iv_path ).
READ TABLE mt_json_tree
ASSIGNING <item>
WITH KEY
path = ls_path_name-path
name = ls_path_name-name.
IF sy-subrc = 0.
GET REFERENCE OF <item> INTO rv_item.
ENDIF.
ENDMETHOD.
METHOD parse.
DATA lo_parser TYPE REF TO lcl_json_parser.
CREATE OBJECT ro_instance.
CREATE OBJECT lo_parser.
ro_instance->mt_json_tree = lo_parser->parse( iv_json ).
ro_instance->mi_custom_mapping = ii_custom_mapping.
IF iv_freeze = abap_true.
ro_instance->freeze( ).
ENDIF.
ENDMETHOD.
METHOD prove_path_exists.
DATA lt_path TYPE string_table.
DATA lr_node LIKE LINE OF rt_node_stack.
DATA lr_node_parent LIKE LINE OF rt_node_stack.
DATA lv_cur_path TYPE string.
DATA lv_cur_name TYPE string.
DATA ls_new_node LIKE LINE OF mt_json_tree.
SPLIT iv_path AT '/' INTO TABLE lt_path.
DELETE lt_path WHERE table_line IS INITIAL.
DO.
lr_node_parent = lr_node.
READ TABLE mt_json_tree REFERENCE INTO lr_node
WITH KEY
path = lv_cur_path
name = lv_cur_name.
IF sy-subrc <> 0. " New node, assume it is always object as it has a named child, use touch_array to init array
CLEAR ls_new_node.
IF lr_node_parent IS NOT INITIAL. " if has parent
lr_node_parent->children = lr_node_parent->children + 1.
IF lr_node_parent->type = zif_abapgit_ajson=>node_type-array.
ls_new_node-index = lcl_utils=>validate_array_index(
iv_path = lv_cur_path
iv_index = lv_cur_name ).
ENDIF.
ENDIF.
ls_new_node-path = lv_cur_path.
ls_new_node-name = lv_cur_name.
ls_new_node-type = zif_abapgit_ajson=>node_type-object.
INSERT ls_new_node INTO TABLE mt_json_tree REFERENCE INTO lr_node.
ENDIF.
INSERT lr_node INTO rt_node_stack INDEX 1.
lv_cur_path = lv_cur_path && lv_cur_name && '/'.
READ TABLE lt_path INDEX sy-index INTO lv_cur_name.
IF sy-subrc <> 0.
EXIT. " no more segments
ENDIF.
ENDDO.
ASSERT lv_cur_path = iv_path. " Just in case
ENDMETHOD.
METHOD zif_abapgit_ajson~array_to_string_table.
DATA lv_normalized_path TYPE string.
DATA lr_node TYPE REF TO zif_abapgit_ajson=>ty_node.
FIELD-SYMBOLS <item> LIKE LINE OF mt_json_tree.
lv_normalized_path = lcl_utils=>normalize_path( iv_path ).
lr_node = get_item( iv_path ).
IF lr_node IS INITIAL.
zcx_abapgit_ajson_error=>raise( |Path not found: { iv_path }| ).
ENDIF.
IF lr_node->type <> zif_abapgit_ajson=>node_type-array.
zcx_abapgit_ajson_error=>raise( |Array expected at: { iv_path }| ).
ENDIF.
LOOP AT mt_json_tree ASSIGNING <item> WHERE path = lv_normalized_path.
CASE <item>-type.
WHEN zif_abapgit_ajson=>node_type-number OR zif_abapgit_ajson=>node_type-string.
APPEND <item>-value TO rt_string_table.
WHEN zif_abapgit_ajson=>node_type-null.
APPEND '' TO rt_string_table.
WHEN zif_abapgit_ajson=>node_type-boolean.
DATA lv_tmp TYPE string.
IF <item>-value = 'true'.
lv_tmp = abap_true.
ELSE.
CLEAR lv_tmp.
ENDIF.
APPEND lv_tmp TO rt_string_table.
WHEN OTHERS.
zcx_abapgit_ajson_error=>raise( |Cannot convert [{ <item>-type
}] to string at [{ <item>-path }{ <item>-name }]| ).
ENDCASE.
ENDLOOP.
ENDMETHOD.
METHOD zif_abapgit_ajson~clear.
IF mv_read_only = abap_true.
zcx_abapgit_ajson_error=>raise( 'This json instance is read only' ).
ENDIF.
CLEAR mt_json_tree.
ENDMETHOD.
METHOD zif_abapgit_ajson~delete.
IF mv_read_only = abap_true.
zcx_abapgit_ajson_error=>raise( 'This json instance is read only' ).
ENDIF.
DATA ls_split_path TYPE zif_abapgit_ajson=>ty_path_name.
ls_split_path = lcl_utils=>split_path( iv_path ).
delete_subtree(
iv_path = ls_split_path-path
iv_name = ls_split_path-name ).
ri_json = me.
ENDMETHOD.
METHOD zif_abapgit_ajson~exists.
DATA lv_item TYPE REF TO zif_abapgit_ajson=>ty_node.
lv_item = get_item( iv_path ).
IF lv_item IS NOT INITIAL.
rv_exists = abap_true.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson~freeze.
mv_read_only = abap_true.
ENDMETHOD.
METHOD zif_abapgit_ajson~get.
DATA lv_item TYPE REF TO zif_abapgit_ajson=>ty_node.
lv_item = get_item( iv_path ).
IF lv_item IS NOT INITIAL.
rv_value = lv_item->value.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson~get_boolean.
DATA lv_item TYPE REF TO zif_abapgit_ajson=>ty_node.
lv_item = get_item( iv_path ).
IF lv_item IS INITIAL OR lv_item->type = zif_abapgit_ajson=>node_type-null.
RETURN.
ELSEIF lv_item->type = zif_abapgit_ajson=>node_type-boolean.
rv_value = boolc( lv_item->value = 'true' ).
ELSEIF lv_item->value IS NOT INITIAL.
rv_value = abap_true.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson~get_date.
DATA lv_item TYPE REF TO zif_abapgit_ajson=>ty_node.
DATA lv_y TYPE c LENGTH 4.
DATA lv_m TYPE c LENGTH 2.
DATA lv_d TYPE c LENGTH 2.
lv_item = get_item( iv_path ).
IF lv_item IS NOT INITIAL AND lv_item->type = zif_abapgit_ajson=>node_type-string.
FIND FIRST OCCURRENCE OF REGEX '^(\d{4})-(\d{2})-(\d{2})(T|$)'
IN lv_item->value
SUBMATCHES lv_y lv_m lv_d.
CONCATENATE lv_y lv_m lv_d INTO rv_value.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson~get_integer.
DATA lv_item TYPE REF TO zif_abapgit_ajson=>ty_node.
lv_item = get_item( iv_path ).
IF lv_item IS NOT INITIAL AND lv_item->type = zif_abapgit_ajson=>node_type-number.
rv_value = lv_item->value.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson~get_node_type.
DATA lv_item TYPE REF TO zif_abapgit_ajson=>ty_node.
lv_item = get_item( iv_path ).
IF lv_item IS NOT INITIAL.
rv_node_type = lv_item->type.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson~get_number.
DATA lv_item TYPE REF TO zif_abapgit_ajson=>ty_node.
lv_item = get_item( iv_path ).
IF lv_item IS NOT INITIAL AND lv_item->type = zif_abapgit_ajson=>node_type-number.
rv_value = lv_item->value.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson~get_string.
DATA lv_item TYPE REF TO zif_abapgit_ajson=>ty_node.
lv_item = get_item( iv_path ).
IF lv_item IS NOT INITIAL AND lv_item->type <> zif_abapgit_ajson=>node_type-null.
rv_value = lv_item->value.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_ajson~get_timestamp.
DATA lo_to_abap TYPE REF TO lcl_json_to_abap.
DATA lr_item TYPE REF TO zif_abapgit_ajson=>ty_node.
lr_item = get_item( iv_path ).
IF lr_item IS INITIAL.
RETURN.
ENDIF.
CREATE OBJECT lo_to_abap.
TRY.
rv_value = lo_to_abap->to_timestamp( is_path = lr_item->* ).
CATCH zcx_abapgit_ajson_error.
RETURN.
ENDTRY.
ENDMETHOD.
METHOD zif_abapgit_ajson~keep_item_order.
mv_keep_item_order = abap_true.
ri_json = me.
ENDMETHOD.
METHOD zif_abapgit_ajson~members.
DATA lv_normalized_path TYPE string.
FIELD-SYMBOLS <item> LIKE LINE OF mt_json_tree.
lv_normalized_path = lcl_utils=>normalize_path( iv_path ).
LOOP AT mt_json_tree ASSIGNING <item> WHERE path = lv_normalized_path.
APPEND <item>-name TO rt_members.
ENDLOOP.
ENDMETHOD.
METHOD zif_abapgit_ajson~push.
DATA lr_parent TYPE REF TO zif_abapgit_ajson=>ty_node.
DATA lr_new_node TYPE REF TO zif_abapgit_ajson=>ty_node.
IF mv_read_only = abap_true.
zcx_abapgit_ajson_error=>raise( 'This json instance is read only' ).
ENDIF.
lr_parent = get_item( iv_path ).
IF lr_parent IS INITIAL.
zcx_abapgit_ajson_error=>raise( |Path [{ iv_path }] does not exist| ).
ENDIF.
IF lr_parent->type <> zif_abapgit_ajson=>node_type-array.
zcx_abapgit_ajson_error=>raise( |Path [{ iv_path }] is not array| ).
ENDIF.
DATA lt_new_nodes TYPE zif_abapgit_ajson=>ty_nodes_tt.
DATA ls_new_path TYPE zif_abapgit_ajson=>ty_path_name.
ls_new_path-path = lcl_utils=>normalize_path( iv_path ).
ls_new_path-name = |{ lr_parent->children + 1 }|.
lt_new_nodes = lcl_abap_to_json=>convert(
iv_keep_item_order = mv_keep_item_order
iv_data = iv_val
is_prefix = ls_new_path ).
READ TABLE lt_new_nodes INDEX 1 REFERENCE INTO lr_new_node. " assume first record is the array item - not ideal !
ASSERT sy-subrc = 0.
lr_new_node->index = lr_parent->children + 1.
" update data
lr_parent->children = lr_parent->children + 1.
INSERT LINES OF lt_new_nodes INTO TABLE mt_json_tree.
ri_json = me.
ENDMETHOD.
METHOD zif_abapgit_ajson~set.
DATA ls_split_path TYPE zif_abapgit_ajson=>ty_path_name.
DATA lr_parent TYPE REF TO zif_abapgit_ajson=>ty_node.
DATA lt_node_stack TYPE tty_node_stack.
IF mv_read_only = abap_true.
zcx_abapgit_ajson_error=>raise( 'This json instance is read only' ).
ENDIF.
ri_json = me.
IF iv_val IS INITIAL AND iv_ignore_empty = abap_true AND iv_node_type IS INITIAL.
RETURN. " nothing to assign
ENDIF.
IF iv_node_type IS NOT INITIAL
AND iv_node_type <> zif_abapgit_ajson=>node_type-boolean AND iv_node_type <> zif_abapgit_ajson=>node_type-null
AND iv_node_type <> zif_abapgit_ajson=>node_type-number AND iv_node_type <> zif_abapgit_ajson=>node_type-string.
zcx_abapgit_ajson_error=>raise( |Unexpected type { iv_node_type }| ).
ENDIF.
ls_split_path = lcl_utils=>split_path( iv_path ).
IF ls_split_path IS INITIAL. " Assign root, exceptional processing
IF iv_node_type IS NOT INITIAL.
mt_json_tree = lcl_abap_to_json=>insert_with_type(
iv_keep_item_order = mv_keep_item_order
iv_data = iv_val
iv_type = iv_node_type
is_prefix = ls_split_path
ii_custom_mapping = mi_custom_mapping ).
ELSE.
mt_json_tree = lcl_abap_to_json=>convert(
iv_keep_item_order = mv_keep_item_order
iv_data = iv_val
is_prefix = ls_split_path
ii_custom_mapping = mi_custom_mapping ).
ENDIF.
RETURN.
ENDIF.
" Ensure whole path exists
lt_node_stack = prove_path_exists( ls_split_path-path ).
READ TABLE lt_node_stack INDEX 1 INTO lr_parent.
ASSERT sy-subrc = 0.
" delete if exists with subtree
delete_subtree(
iv_path = ls_split_path-path
iv_name = ls_split_path-name ).
" convert to json
DATA lt_new_nodes TYPE zif_abapgit_ajson=>ty_nodes_tt.
DATA lv_array_index TYPE i.
IF lr_parent->type = zif_abapgit_ajson=>node_type-array.
lv_array_index = lcl_utils=>validate_array_index(
iv_path = ls_split_path-path
iv_index = ls_split_path-name ).
ENDIF.
IF iv_node_type IS NOT INITIAL.
lt_new_nodes = lcl_abap_to_json=>insert_with_type(
iv_keep_item_order = mv_keep_item_order
iv_data = iv_val
iv_type = iv_node_type
iv_array_index = lv_array_index
is_prefix = ls_split_path
ii_custom_mapping = mi_custom_mapping ).
ELSE.
lt_new_nodes = lcl_abap_to_json=>convert(
iv_keep_item_order = mv_keep_item_order
iv_data = iv_val
iv_array_index = lv_array_index
is_prefix = ls_split_path
ii_custom_mapping = mi_custom_mapping ).
ENDIF.
" update data
lr_parent->children = lr_parent->children + 1.
INSERT LINES OF lt_new_nodes INTO TABLE mt_json_tree.
ENDMETHOD.
METHOD zif_abapgit_ajson~set_boolean.
ri_json = me.
DATA lv_bool TYPE abap_bool.
lv_bool = boolc( iv_val IS NOT INITIAL ).
zif_abapgit_ajson~set(
iv_ignore_empty = abap_false
iv_path = iv_path
iv_val = lv_bool ).
ENDMETHOD.
METHOD zif_abapgit_ajson~set_date.
ri_json = me.
DATA lv_val TYPE string.
IF iv_val IS NOT INITIAL.
lv_val = iv_val+0(4) && '-' && iv_val+4(2) && '-' && iv_val+6(2).
ENDIF.
zif_abapgit_ajson~set(
iv_ignore_empty = abap_false
iv_path = iv_path
iv_val = lv_val ).
ENDMETHOD.
METHOD zif_abapgit_ajson~set_integer.
ri_json = me.
zif_abapgit_ajson~set(
iv_ignore_empty = abap_false
iv_path = iv_path
iv_val = iv_val ).
ENDMETHOD.
METHOD zif_abapgit_ajson~set_null.
ri_json = me.
DATA lv_null_ref TYPE REF TO data.
zif_abapgit_ajson~set(
iv_ignore_empty = abap_false
iv_path = iv_path
iv_val = lv_null_ref ).
ENDMETHOD.
METHOD zif_abapgit_ajson~set_string.
ri_json = me.
DATA lv_val TYPE string.
lv_val = iv_val.
zif_abapgit_ajson~set(
iv_ignore_empty = abap_false
iv_path = iv_path
iv_val = lv_val ).
ENDMETHOD.
METHOD zif_abapgit_ajson~set_timestamp.
CONSTANTS lc_utc TYPE c LENGTH 6 VALUE 'UTC'.
DATA:
lv_date TYPE d,
lv_time TYPE t,
lv_timestamp_iso TYPE string.
ri_json = me.
IF iv_val IS INITIAL.
" The zero value is January 1, year 1, 00:00:00.000000000 UTC.
lv_date = '00010101'.
ELSE.
CONVERT TIME STAMP iv_val TIME ZONE lc_utc
INTO DATE lv_date TIME lv_time.
ENDIF.
lv_timestamp_iso =
lv_date+0(4) && '-' && lv_date+4(2) && '-' && lv_date+6(2) &&
'T' &&
lv_time+0(2) && '-' && lv_time+2(2) && '-' && lv_time+4(2) &&
'Z'.
zif_abapgit_ajson~set(
iv_ignore_empty = abap_false
iv_path = iv_path
iv_val = lv_timestamp_iso ).
ENDMETHOD.
METHOD zif_abapgit_ajson~slice.
DATA lo_section TYPE REF TO zcl_abapgit_ajson.
DATA ls_item LIKE LINE OF mt_json_tree.
DATA lv_normalized_path TYPE string.
DATA ls_path_parts TYPE zif_abapgit_ajson=>ty_path_name.
DATA lv_path_len TYPE i.
CREATE OBJECT lo_section.
lv_normalized_path = lcl_utils=>normalize_path( iv_path ).
lv_path_len = strlen( lv_normalized_path ).
ls_path_parts = lcl_utils=>split_path( lv_normalized_path ).
LOOP AT mt_json_tree INTO ls_item.
" TODO potentially improve performance due to sorted tree (all path started from same prefix go in a row)
IF strlen( ls_item-path ) >= lv_path_len
AND substring( val = ls_item-path
len = lv_path_len ) = lv_normalized_path.
ls_item-path = substring( val = ls_item-path
off = lv_path_len - 1 ). " less closing '/'
INSERT ls_item INTO TABLE lo_section->mt_json_tree.
ELSEIF ls_item-path = ls_path_parts-path AND ls_item-name = ls_path_parts-name.
CLEAR: ls_item-path, ls_item-name. " this becomes a new root
INSERT ls_item INTO TABLE lo_section->mt_json_tree.
ENDIF.
ENDLOOP.
ri_json = lo_section.
ENDMETHOD.
METHOD zif_abapgit_ajson~stringify.
rv_json = lcl_json_serializer=>stringify(
it_json_tree = mt_json_tree
iv_keep_item_order = mv_keep_item_order
iv_indent = iv_indent ).
ENDMETHOD.
METHOD zif_abapgit_ajson~touch_array.
DATA lr_node TYPE REF TO zif_abapgit_ajson=>ty_node.
DATA ls_new_node LIKE LINE OF mt_json_tree.
DATA ls_split_path TYPE zif_abapgit_ajson=>ty_path_name.
IF mv_read_only = abap_true.
zcx_abapgit_ajson_error=>raise( 'This json instance is read only' ).
ENDIF.
ls_split_path = lcl_utils=>split_path( iv_path ).
IF ls_split_path IS INITIAL. " Assign root, exceptional processing
ls_new_node-path = ls_split_path-path.
ls_new_node-name = ls_split_path-name.
ls_new_node-type = 'array'.
INSERT ls_new_node INTO TABLE mt_json_tree.
RETURN.
ENDIF.
IF iv_clear = abap_true.
delete_subtree(
iv_path = ls_split_path-path
iv_name = ls_split_path-name ).
ELSE.
lr_node = get_item( iv_path ).
ENDIF.
IF lr_node IS INITIAL. " Or node was cleared
DATA lr_parent TYPE REF TO zif_abapgit_ajson=>ty_node.
DATA lt_node_stack TYPE tty_node_stack.
lt_node_stack = prove_path_exists( ls_split_path-path ).
READ TABLE lt_node_stack INDEX 1 INTO lr_parent.
ASSERT sy-subrc = 0.
lr_parent->children = lr_parent->children + 1.
ls_new_node-path = ls_split_path-path.
ls_new_node-name = ls_split_path-name.
ls_new_node-type = zif_abapgit_ajson=>node_type-array.
INSERT ls_new_node INTO TABLE mt_json_tree.
ELSEIF lr_node->type <> zif_abapgit_ajson=>node_type-array.
zcx_abapgit_ajson_error=>raise( |Path [{ iv_path }] already used and is not array| ).
ENDIF.
ri_json = me.
ENDMETHOD.
METHOD zif_abapgit_ajson~to_abap.
DATA lo_to_abap TYPE REF TO lcl_json_to_abap.
CLEAR ev_container.
lcl_json_to_abap=>bind(
EXPORTING
ii_custom_mapping = mi_custom_mapping
CHANGING
c_obj = ev_container
co_instance = lo_to_abap ).
lo_to_abap->to_abap( mt_json_tree ).
ENDMETHOD.
ENDCLASS.