Skip to Content
avatar image
Former Member

JSON to ABAP Create Data Dynamically?

Hi,

How can i create data from complex json. This data nested structure. Also can be contain array in array line. It is so complex :)

Example JSON;

[
  {
    "MATKL": "Mal Grubu 1",
    "ATTRB": {
      "TYPE": "A",
      "BRANCH": "B"
    },
    "MATNR": [
      {
        "NAME": "Malzeme 1",
        "WEIGHT": "12,2",
        "LENGTH": "",
        "UoM": "KG"
      }
    ]
  },
  {
    "MATKL": "Mal Grubu 1",
    "ATTRB": {
      "TYPE": "A",
      "BRANCH": "B"
    },
    "MATNR": [
      {
        "NAME": "Malzeme 1",
        "WEIGHT": "12,2",
        "LENGTH": "",
        "UoM": "KG"
      }
    ]
  }
]


Its output like that;

I need to seperate all json data into my dynamic structure type then i will use it update my z tables.

Call transformation statement's result parameter must be same type json data. If not contain same fields. I cant transfer it to internal table completly.

Note : Standard class or function module can be use in old SAP version(Kernel Id).

How can i solve it? Please help.

Thanks for your valuable answers.

json.png (10.9 kB)
Add comment
10|10000 characters needed characters exceeded

  • Get RSS Feed

4 Answers

  • Jan 16 at 01:24 PM

    You can dynamicaly parse JSON with sxml_writer.

    There is example program named demo_json_oo_reader

    It is also in abapdocu: https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abenabap_json_oo_reader_abexa.htm

    Add comment
    10|10000 characters needed characters exceeded

  • Jan 16 at 07:24 PM

    See this SAP-Blog on ABAP and JSON : link

    SAP-Help provides Info and Samples on Parsing JSON : link

    Other Samples on JSON Serialize / De-Serializer Wiki-page make the case for using Classes "/UI5/CL_JSON_PARSER" and "/UI5/CL_JSON" : link

    I would suggest looking into the Wiki-CodeSamples and using "/UI5/CL_JSON" for Parsing JSON in a 'known' format, and "/UI5/CL_JSON_PARSER" when handling 'unknown' data ...

    Add comment
    10|10000 characters needed characters exceeded

  • Jan 16 at 08:03 PM
    Add comment
    10|10000 characters needed characters exceeded

  • avatar image
    Former Member
    Jan 19 at 11:23 AM

    Thanks for your all valuable answers. I found below solution for my requirements. The next step is create dynamically data from json string. Now, below solution is without kernel version so enogh for me.

    Also, you can use alternative solution SAP standard method : cl_fdt_json

    Go to Github link see for all content

    * Rather use https://gist.github.com/mydoghasworms/4888a832e28491c3fe47
    * The alternative is a better parser although it is not an emmitter)
    *----------------------------------------------------------------------*
    *       CLASS json_util DEFINITION
    *---------------------------------------------------------------------*
    CLASS json_util DEFINITION.
      PUBLIC SECTION.
        CLASS-METHODS:
          data_to_json IMPORTING data TYPE any
                       RETURNING value(json) TYPE string,
    
          json_to_data IMPORTING json TYPE string
                       CHANGING data TYPE any.
    
    ENDCLASS.                    "json_util DEFINITION
    
    *----------------------------------------------------------------------*
    *       CLASS json_util IMPLEMENTATION
    *----------------------------------------------------------------------*
    CLASS json_util IMPLEMENTATION.
      METHOD data_to_json.
        DATA: lr_desc TYPE REF TO cl_abap_typedescr.
        DATA: lr_elem TYPE REF TO cl_abap_elemdescr.
        DATA: lr_sdes TYPE REF TO cl_abap_structdescr.
        DATA: ls_comp TYPE cl_abap_structdescr=>component.
        DATA: lt_comp TYPE cl_abap_structdescr=>component_table.
        DATA: lv_json TYPE string.
        DATA: lv_field TYPE string.
        DATA: lv_value TYPE text255.
    
        FIELD-SYMBOLS: <field> TYPE any.
    
        DATA: lt_x031l TYPE dd_x031l_table.
        DATA: ls_x031l TYPE x031l.
        DATA: ls_dfies TYPE dfies.
        DATA: lv_meth(30) TYPE c VALUE 'GET_DDIC_FIELD'.
        DATA: lv_date TYPE d.
        DATA: lv_date_c(10) TYPE c.
        DATA: lv_time TYPE t.
        DATA: lv_time_c(8) TYPE c.
        DATA: lv_tabix TYPE i.
        DATA: lv_index TYPE i.
        DATA: lv_passed1st TYPE boole_d.
    
        lr_desc = cl_abap_typedescr=>describe_by_data( data ).
    
        CASE lr_desc->type_kind.
    
          WHEN cl_abap_typedescr=>typekind_struct1 OR cl_abap_typedescr=>typekind_struct2.
            json = '{'.
    * Use RTTI to discover structure members and process them individually
            lr_sdes ?= lr_desc.
            lt_comp = lr_sdes->get_components( ).
            LOOP AT lt_comp INTO ls_comp.
    
    
              ASSIGN COMPONENT ls_comp-name OF STRUCTURE data
    
                TO <field>.
    
              IF sy-subrc = 0 AND <field> IS NOT INITIAL.
    
    * For consecutive elements, add a comma separator after the previous value
                IF lv_passed1st = 'X'.
    
                  CONCATENATE json ',' INTO json.
    
                ENDIF.
    
    
    
                lv_json = data_to_json( data = <field> ).
    
    
    
                CONCATENATE json ' "' ls_comp-name '": ' lv_json INTO json.
    
    
    
                lv_passed1st = 'X'.
    
              ENDIF.
    
    
    
            ENDLOOP.
    
            CONCATENATE json '}' INTO json.
    
          WHEN cl_abap_typedescr=>typekind_table.
    
            DATA: ld_line TYPE REF TO data.
    
            FIELD-SYMBOLS: <tab> TYPE ANY TABLE.
    
            FIELD-SYMBOLS: <line> TYPE any.
    
            ASSIGN data TO <tab>.
    
            CREATE DATA ld_line LIKE LINE OF <tab>.
    
            ASSIGN ld_line->* TO <line>.
    
    
    
    * Open array for table entries
    
            json = '['.
    
    
    
            LOOP AT <tab> INTO <line>.
    
              lv_json = data_to_json( data = <line> ).
    
              CONCATENATE json lv_json INTO json SEPARATED BY space.
    
              AT LAST.
    
                CONTINUE.
    
              ENDAT.
    
    * Separate consecutive values by commas
    
              CONCATENATE json ',' INTO json.
    
            ENDLOOP.
    
    
    
    * Close array for table entries
    
            CONCATENATE json ']' INTO json SEPARATED BY space.
    
    
    
          WHEN cl_abap_typedescr=>typekind_dref.
    
    * For data references, dereference the data and call method again
    
            FIELD-SYMBOLS: <data> TYPE any.
    
            ASSIGN data->* TO <data>.
    
            IF sy-subrc = 0.
    
              json = data_to_json( data = <data> ).
    
            ELSE.
    
              json = '{}'. "Will produce empty JS object
    
            ENDIF.
    
          WHEN OTHERS.
    
    * For elementary types, we merely return a text representation of the value
    
            json = data.
    
            CONDENSE json.
    
    
    
    * Escape special characters
    
            REPLACE ALL OCCURRENCES OF '\'                                    IN json WITH '\\'.
    
            REPLACE ALL OCCURRENCES OF '"'                                    IN json WITH '\"'.
    
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline        IN json WITH '\n'.
    
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>horizontal_tab IN json WITH '\t'.
    
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>form_feed      IN json WITH '\f'.
    
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>vertical_tab   IN json WITH '\v'.
    
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>backspace      IN json WITH '\b'.
    
    
    
    * Numeric values do not need to be escaped
    
            IF lr_desc->type_kind NE cl_abap_typedescr=>typekind_num AND
    
               lr_desc->type_kind NE cl_abap_typedescr=>typekind_packed AND
    
               lr_desc->type_kind NE cl_abap_typedescr=>typekind_float AND
    
               lr_desc->type_kind NE cl_abap_typedescr=>typekind_int AND
    
               lr_desc->type_kind NE cl_abap_typedescr=>typekind_int1 AND
    
               lr_desc->type_kind NE cl_abap_typedescr=>typekind_int2.
    
              CONCATENATE '"' json '"' INTO json.
    
            ENDIF.
    
    
    
        ENDCASE.
    
    
    
      ENDMETHOD.                    "data_to_json
    
    
    
      METHOD json_to_data.
    
        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.
    
                json_to_data( EXPORTING json = lv_value CHANGING data = <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.
    
                json_to_data( EXPORTING json = lv_key CHANGING data = <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.
    
      ENDMETHOD.                    "json_to_data
    
    ENDCLASS.                    "json_util IMPLEMENTATION
    
    
    
    START-OF-SELECTION.
    
    
    
      DATA : go_json TYPE REF TO json_util.
    
    
    
      DATA : gv_json TYPE string,
    
             gt_itab TYPE ztest_tt_001.
    
    
    
      gv_json =
    
      '[{"MATKL":"Mal Grubu 1","ATTRB":{"TYPE":"A","BRANCH":"B"},"MATERIAL":[{"NAME":"Malzeme 1","WEIGHT":"12,2","LENGTH":"","UoM":"KG"}]}]'.
    
    
    
      CREATE OBJECT go_json.
    
    
    
      CALL METHOD go_json->json_to_data
    
        EXPORTING
    
          json = gv_json
    
        CHANGING
    
          data = gt_itab.
    
    
    
      BREAK-POINT.
    Add comment
    10|10000 characters needed characters exceeded