diff --git a/src/#mbtools#cl_ajson.clas.abap b/src/#mbtools#cl_ajson.clas.abap index 661d639..e5a1cb7 100644 --- a/src/#mbtools#cl_ajson.clas.abap +++ b/src/#mbtools#cl_ajson.clas.abap @@ -848,6 +848,8 @@ CLASS /mbtools/cl_ajson IMPLEMENTATION. DATA lv_path_pattern TYPE string. CREATE OBJECT lo_section. + lo_section->mi_custom_mapping = mi_custom_mapping. + 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 ). diff --git a/src/#mbtools#cl_ajson.clas.locals_imp.abap b/src/#mbtools#cl_ajson.clas.locals_imp.abap index 7b7bd2a..037a766 100644 --- a/src/#mbtools#cl_ajson.clas.locals_imp.abap +++ b/src/#mbtools#cl_ajson.clas.locals_imp.abap @@ -223,6 +223,12 @@ CLASS lcl_utils IMPLEMENTATION. rv_path_name-name = substring( val = iv_path off = lv_offs len = lv_len - lv_offs - lv_trim_slash ). + " Replace tabs with slash to get original value + rv_path_name-name = replace( + val = rv_path_name-name + sub = cl_abap_char_utilities=>horizontal_tab + with = '/' + occ = 0 ). ENDMETHOD. @@ -475,8 +481,13 @@ CLASS lcl_json_parser IMPLEMENTATION. GET REFERENCE OF INTO lr_stack_top. INSERT lr_stack_top INTO mt_stack INDEX 1. - " add path component - mv_stack_path = mv_stack_path && -name && '/'. + " add path component (avoid issues with names containing slashes) + mv_stack_path = mv_stack_path && replace( + val = -name + sub = '/' + with = cl_abap_char_utilities=>horizontal_tab + occ = 0 ) + && '/'. WHEN if_sxml_node=>co_nt_element_close. DATA lo_close TYPE REF TO if_sxml_close_element. diff --git a/src/#mbtools#cl_ajson.clas.testclasses.abap b/src/#mbtools#cl_ajson.clas.testclasses.abap index d104498..78bfbfc 100644 --- a/src/#mbtools#cl_ajson.clas.testclasses.abap +++ b/src/#mbtools#cl_ajson.clas.testclasses.abap @@ -91,6 +91,9 @@ CLASS ltcl_parser_test DEFINITION FINAL METHODS parse_input_error FOR TESTING RAISING /mbtools/cx_ajson_error. METHODS duplicate_key FOR TESTING RAISING /mbtools/cx_ajson_error. METHODS non_json FOR TESTING RAISING /mbtools/cx_ajson_error. + METHODS special_characters_in_name FOR TESTING RAISING /mbtools/cx_ajson_error. + METHODS special_characters_in_path FOR TESTING RAISING /mbtools/cx_ajson_error. + METHODS special_characters_in_value FOR TESTING RAISING /mbtools/cx_ajson_error. ENDCLASS. @@ -515,6 +518,86 @@ CLASS ltcl_parser_test IMPLEMENTATION. ENDMETHOD. + METHOD special_characters_in_name. + mo_nodes->add( | \| \|object \| \| \|7| ). + mo_nodes->add( |/ \|a\\backslash \|num \|1 \| \|0| ). + mo_nodes->add( |/ \|contains/slash \|num \|2 \| \|0| ). + mo_nodes->add( |/ \|unicodeሴ \|num \|3 \| \|0| ). + mo_nodes->add( |/ \|quoted"text" \|num \|4 \| \|0| ). + mo_nodes->add( |/ \|line\nfeed \|num \|5 \| \|0| ). + mo_nodes->add( |/ \|with\ttab \|num \|6 \| \|0| ). + mo_nodes->add( |/ \|one/two/slash \|num \|7 \| \|0| ). + + DATA lt_act TYPE /mbtools/if_ajson_types=>ty_nodes_tt. + DATA lv_str TYPE string. + + lv_str = '{ "a\\backslash": 1, "contains/slash": 2, "unicode\u1234": 3,' + && ' "quoted\"text\"": 4, "line\nfeed": 5, "with\ttab": 6,' + && ' "one/two/slash": 7 }'. + lt_act = mo_cut->parse( lv_str ). + + cl_abap_unit_assert=>assert_equals( + act = lt_act + exp = mo_nodes->mt_nodes ). + + ENDMETHOD. + + METHOD special_characters_in_path. + mo_nodes->add( | \| \|object \| \| \|7| ). + mo_nodes->add( |/ \|a\\backslash \|object \| \| \|1| ). + mo_nodes->add( |/a\\backslash/ \|a \|num \|1 \| \|0| ). + mo_nodes->add( |/ \|contains/slash \|object \| \| \|1| ). + mo_nodes->add( |/contains\tslash/\|b \|num \|2 \| \|0| ). " tab! + mo_nodes->add( |/ \|unicodeሴ \|object \| \| \|1| ). + mo_nodes->add( |/unicodeሴ/ \|c \|num \|3 \| \|0| ). + mo_nodes->add( |/ \|quoted"text" \|object \| \| \|1| ). + mo_nodes->add( |/quoted"text"/ \|d \|num \|4 \| \|0| ). + mo_nodes->add( |/ \|line\nfeed \|object \| \| \|1| ). + mo_nodes->add( |/line\nfeed/ \|e \|num \|5 \| \|0| ). + mo_nodes->add( |/ \|with\ttab \|object \| \| \|1| ). + mo_nodes->add( |/with\ttab/ \|f \|num \|6 \| \|0| ). + mo_nodes->add( |/ \|one/two/slash \|object \| \| \|1| ). + mo_nodes->add( |/one\ttwo\tslash/\|g \|num \|7 \| \|0| ). " tab! + + DATA lt_act TYPE /mbtools/if_ajson_types=>ty_nodes_tt. + DATA lv_str TYPE string. + + lv_str = '{ "a\\backslash": { "a": 1 }, "contains/slash": { "b": 2 },' + && ' "unicode\u1234": { "c": 3 }, "quoted\"text\"": { "d": 4 },' + && ' "line\nfeed": { "e": 5 }, "with\ttab": { "f": 6 },' + && ' "one/two/slash": { "g": 7 } }'. + lt_act = mo_cut->parse( lv_str ). + + cl_abap_unit_assert=>assert_equals( + act = lt_act + exp = mo_nodes->mt_nodes ). + + ENDMETHOD. + + METHOD special_characters_in_value. + mo_nodes->add( | \| \|object \| \| \|7| ). + mo_nodes->add( |/ \|a \|str \|a\\backslash \| \|0| ). + mo_nodes->add( |/ \|b \|str \|contains/slash \| \|0| ). + mo_nodes->add( |/ \|c \|str \|unicodeሴ \| \|0| ). + mo_nodes->add( |/ \|d \|str \|quoted"text" \| \|0| ). + mo_nodes->add( |/ \|e \|str \|line\nfeed \| \|0| ). + mo_nodes->add( |/ \|f \|str \|with\ttab \| \|0| ). + mo_nodes->add( |/ \|g \|str \|one/two/slash \| \|0| ). + + DATA lt_act TYPE /mbtools/if_ajson_types=>ty_nodes_tt. + DATA lv_str TYPE string. + + lv_str = '{ "a": "a\\backslash", "b": "contains/slash", "c": "unicode\u1234",' + && ' "d": "quoted\"text\"", "e": "line\nfeed", "f": "with\ttab",' + && ' "g": "one/two/slash" }'. + lt_act = mo_cut->parse( lv_str ). + + cl_abap_unit_assert=>assert_equals( + act = lt_act + exp = mo_nodes->mt_nodes ). + + ENDMETHOD. + ENDCLASS. ********************************************************************** @@ -699,6 +782,7 @@ CLASS ltcl_serializer_test IMPLEMENTATION. iv_indent = 2 ). lv_exp = sample_json( ). + cl_abap_unit_assert=>assert_equals( act = lv_act exp = lv_exp ). diff --git a/src/#mbtools#cl_ajson_filter_lib.clas.locals_imp.abap b/src/#mbtools#cl_ajson_filter_lib.clas.locals_imp.abap index 8959277..f71dfa4 100644 --- a/src/#mbtools#cl_ajson_filter_lib.clas.locals_imp.abap +++ b/src/#mbtools#cl_ajson_filter_lib.clas.locals_imp.abap @@ -72,7 +72,7 @@ CLASS lcl_paths_filter IMPLEMENTATION. ENDIF. LOOP AT it_skip_paths INTO lv_s. - lv_s = to_lower( lv_s ). + lv_s = condense( lv_s ). APPEND lv_s TO lt_tab. ENDLOOP. @@ -83,7 +83,7 @@ CLASS lcl_paths_filter IMPLEMENTATION. DELETE lt_tab INDEX sy-tabix. CONTINUE. ENDIF. - = condense( to_lower( ) ). + = condense( ). ENDLOOP. ENDIF. diff --git a/src/#mbtools#cl_ajson_filter_lib.clas.testclasses.abap b/src/#mbtools#cl_ajson_filter_lib.clas.testclasses.abap index 86887f2..4d425be 100644 --- a/src/#mbtools#cl_ajson_filter_lib.clas.testclasses.abap +++ b/src/#mbtools#cl_ajson_filter_lib.clas.testclasses.abap @@ -10,6 +10,7 @@ CLASS ltcl_filters_test DEFINITION FINAL METHODS path_filter_w_patterns FOR TESTING RAISING /mbtools/cx_ajson_error. METHODS path_filter_deep FOR TESTING RAISING /mbtools/cx_ajson_error. METHODS and_filter FOR TESTING RAISING /mbtools/cx_ajson_error. + METHODS mixed_case_filter FOR TESTING RAISING /mbtools/cx_ajson_error. ENDCLASS. @@ -227,4 +228,36 @@ CLASS ltcl_filters_test IMPLEMENTATION. ENDMETHOD. + METHOD mixed_case_filter. + + DATA li_json TYPE REF TO /mbtools/if_ajson. + DATA li_json_filtered TYPE REF TO /mbtools/if_ajson. + + li_json = /mbtools/cl_ajson=>create_empty( ). + li_json->set( + iv_path = '/a' + iv_val = '1' ). + li_json->set( + iv_path = '/bB' + iv_val = '2' ). + li_json->set( + iv_path = '/CC' + iv_val = '3' ). + li_json->set( + iv_path = '/cc' + iv_val = '4' ). + li_json->set( + iv_path = '/d' + iv_val = 5 ). + + li_json_filtered = /mbtools/cl_ajson=>create_from( + ii_source_json = li_json + ii_filter = /mbtools/cl_ajson_filter_lib=>create_path_filter( iv_skip_paths = '/bB,/CC' ) ). + + cl_abap_unit_assert=>assert_equals( + act = li_json_filtered->stringify( ) + exp = '{"a":"1","cc":"4","d":5}' ). + + ENDMETHOD. + ENDCLASS. diff --git a/src/#mbtools#cl_ajson_mapping.clas.testclasses.abap b/src/#mbtools#cl_ajson_mapping.clas.testclasses.abap index df161fa..8ac92bd 100644 --- a/src/#mbtools#cl_ajson_mapping.clas.testclasses.abap +++ b/src/#mbtools#cl_ajson_mapping.clas.testclasses.abap @@ -358,6 +358,7 @@ CLASS ltcl_fields DEFINITION FINAL FOR TESTING to_json_without_path FOR TESTING RAISING /mbtools/cx_ajson_error, to_json_with_path FOR TESTING RAISING /mbtools/cx_ajson_error, to_abap FOR TESTING RAISING /mbtools/cx_ajson_error, + to_abap_with_slice FOR TESTING RAISING /mbtools/cx_ajson_error, to_json IMPORTING iv_path TYPE string RETURNING VALUE(rv_result) TYPE string RAISING /mbtools/cx_ajson_error. @@ -403,6 +404,33 @@ CLASS ltcl_fields IMPLEMENTATION. ENDMETHOD. + METHOD to_abap_with_slice. + + DATA: BEGIN OF ls_act, + y TYPE i, + END OF ls_act. + + DATA lo_cut TYPE REF TO /mbtools/if_ajson. + DATA lt_mapping_fields TYPE /mbtools/if_ajson_mapping=>ty_mapping_fields. + DATA ls_mapping_field LIKE LINE OF lt_mapping_fields. + + CLEAR ls_mapping_field. + ls_mapping_field-abap = 'Y'. + ls_mapping_field-json = 'c'. + INSERT ls_mapping_field INTO TABLE lt_mapping_fields. + + lo_cut = /mbtools/cl_ajson=>parse( iv_json = '{"a":1,"b":{"c":2},"d":{"e":3}}' + ii_custom_mapping = /mbtools/cl_ajson_mapping=>create_field_mapping( lt_mapping_fields ) + )->slice( `/b` ). + + lo_cut->to_abap( IMPORTING ev_container = ls_act ). + + cl_abap_unit_assert=>assert_equals( + act = ls_act-y + exp = 2 ). + + ENDMETHOD. + METHOD to_json_without_path. diff --git a/src/#mbtools#if_ajson.intf.abap b/src/#mbtools#if_ajson.intf.abap index 6e711b7..42d2af6 100644 --- a/src/#mbtools#if_ajson.intf.abap +++ b/src/#mbtools#if_ajson.intf.abap @@ -1,7 +1,7 @@ INTERFACE /mbtools/if_ajson PUBLIC. - CONSTANTS version TYPE string VALUE 'v1.1.10'. "#EC NOTEXT + CONSTANTS version TYPE string VALUE 'v1.1.11'. "#EC NOTEXT CONSTANTS origin TYPE string VALUE 'https://github.com/sbcgua/ajson'. "#EC NOTEXT CONSTANTS license TYPE string VALUE 'MIT'. "#EC NOTEXT