[ABAP] JSON parsen und in Node-Table wandeln

* Quelle: https://github.com/i042416/KnowlegeRepository/blob/master/ABAP/SmallApp/011_ZCL_JERRY_TOOL.abap
CLASS lcl_json_parser DEFINITION.
  PUBLIC SECTION.

    TYPES: BEGIN OF ty_node,
             type      TYPE string,
             prefix    TYPE string,
             name      TYPE string,
             nsuri     TYPE string,
             value     TYPE string,
             value_raw TYPE xstring,
           END OF ty_node.

    TYPES: ty_it_node TYPE STANDARD TABLE OF ty_node WITH DEFAULT KEY.

    CONSTANTS: co_open_element TYPE string VALUE 'OPEN'.
    CONSTANTS: co_close_element TYPE string VALUE 'CLOSE'.
    CONSTANTS: co_attribute TYPE string VALUE 'ATTRIBUTE'.
    CONSTANTS: co_value TYPE string VALUE 'VALUE'.

    CLASS-METHODS: convert_json_to_node_table
      IMPORTING
                iv_json            TYPE string
      RETURNING VALUE(rv_it_nodes) TYPE ty_it_node
      RAISING
                cx_sxml_parse_error.
ENDCLASS.

CLASS lcl_json_parser IMPLEMENTATION.
  METHOD convert_json_to_node_table.

* JSON nach XSTRING (UTF-8) konvertieren
    DATA(o_json) = cl_abap_codepage=>convert_to( iv_json ).
* XSTRING einlesen und nach XML parsen
    DATA(o_reader) = cl_sxml_string_reader=>create( o_json ).

    TRY.
* erste Node holen
        DATA(o_node) = o_reader->read_next_node( ).

* solange es Nodes gibt
        WHILE o_node IS BOUND.
* Node-Typen prüfen
          CASE o_node->type.
* Öffnen-Node
            WHEN if_sxml_node=>co_nt_element_open.
              DATA(op) = CAST if_sxml_open_element( o_node ).
              APPEND VALUE #( type   = co_open_element
                              prefix = op->prefix
                              name   = op->qname-name
                              nsuri  = op->qname-namespace ) TO rv_it_nodes.

* Attribute
              LOOP AT op->get_attributes( ) ASSIGNING FIELD-SYMBOL(<a>).
                APPEND VALUE #( type      = co_attribute
                                prefix    = <a>->prefix
                                name      = <a>->qname-name
                                nsuri     = <a>->qname-namespace
                                value     = COND #( WHEN <a>->value_type = if_sxml_value=>co_vt_text THEN <a>->get_value( ) )
                                value_raw = COND #( WHEN <a>->value_type = if_sxml_value=>co_vt_raw THEN <a>->get_value_raw( ) ) ) TO rv_it_nodes.
              ENDLOOP.
* Schließen-Node
            WHEN if_sxml_node=>co_nt_element_close.
              DATA(cl) = CAST if_sxml_close_element( o_node ).
              APPEND VALUE #( type   = co_close_element
                              prefix = cl->prefix
                              name   = cl->qname-name
                              nsuri  = cl->qname-namespace ) TO rv_it_nodes.

* Wert-Node
            WHEN if_sxml_node=>co_nt_value.
              DATA(val) = CAST if_sxml_value_node( o_node ).
              APPEND VALUE #( type      = co_value
                              value     = COND #( WHEN val->value_type = if_sxml_value=>co_vt_text THEN val->get_value( ) )
                              value_raw = COND #( WHEN val->value_type = if_sxml_value=>co_vt_raw THEN val->get_value_raw( ) ) ) TO rv_it_nodes.
* Andere Nodetypen
            WHEN OTHERS.

          ENDCASE.

* nächste Node
          o_node = o_reader->read_next_node( ).
        ENDWHILE.

      CATCH cx_root INTO DATA(e_txt).
        RAISE EXCEPTION TYPE cx_sxml_parse_error
          EXPORTING
            error_text = e_txt->get_text( ).
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  TRY.
* JSON-Beispiele
*      DATA(lv_json) = CONV string( '{"success":"true","msg":"Ok.","matnr":"0000001234"}' ).
      DATA(lv_json) = CONV string( '{"VALUES":[{"NAME":"Horst","TITLE":"Herr","AGE":30},{"NAME":"Jutta","TITLE":"Frau","AGE":35},{"NAME":"Ingo","TITLE":"Herr","AGE":31}]}' ).

* JSON -> Nodetable
      DATA(it_node_values) = lcl_json_parser=>convert_json_to_node_table( lv_json ).

* Datenausgabe
      cl_demo_output=>write_data( lv_json ).
      cl_demo_output=>write_data( it_node_values ).
      cl_demo_output=>display( ).
    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.