diff --git a/abaplint.jsonc b/abaplint.jsonc index 61ecf28..f5ed4d8 100644 --- a/abaplint.jsonc +++ b/abaplint.jsonc @@ -73,7 +73,9 @@ "names_no_dash": true, "no_aliases": false, "no_chained_assignment": true, - "7bit_ascii": true, + "7bit_ascii": { + "exclude": ["zcl_ajson.clas.testclasses.abap"] + }, "abapdoc": false, "allowed_object_naming": true, "allowed_object_types": true, diff --git a/src/core/zcl_ajson.clas.locals_imp.abap b/src/core/zcl_ajson.clas.locals_imp.abap index 3901e93..e29f004 100644 --- a/src/core/zcl_ajson.clas.locals_imp.abap +++ b/src/core/zcl_ajson.clas.locals_imp.abap @@ -466,8 +466,12 @@ 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 ) + && '/'. when if_sxml_node=>co_nt_element_close. data lo_close type ref to if_sxml_close_element. diff --git a/src/core/zcl_ajson.clas.testclasses.abap b/src/core/zcl_ajson.clas.testclasses.abap index 8612047..85c25e6 100644 --- a/src/core/zcl_ajson.clas.testclasses.abap +++ b/src/core/zcl_ajson.clas.testclasses.abap @@ -91,6 +91,9 @@ class ltcl_parser_test definition final methods parse_input_error for testing raising zcx_ajson_error. methods duplicate_key for testing raising zcx_ajson_error. methods non_json for testing raising zcx_ajson_error. + methods special_characters_in_name for testing raising zcx_ajson_error. + methods special_characters_in_path for testing raising zcx_ajson_error. + methods special_characters_in_value for testing raising zcx_ajson_error. endclass. @@ -515,6 +518,79 @@ class ltcl_parser_test implementation. endmethod. + method special_characters_in_name. + mo_nodes->add( | \| \|object \| \| \|6| ). + 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| ). + + data lt_act type zif_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 }'. + 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 \| \| \|6| ). + 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| ). + + data lt_act type zif_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 } }'. + 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 \| \| \|6| ). + 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| ). + + data lt_act type zif_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" }'. + 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 +775,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 ).