SAP ABAP 接口函数日志 简化版

日志存储表

ZIF_MSG 结构

MANDT	    MANDT	CLNT	3	0	0	集团
GUID	    APB_LPD_GUID	CHAR	32	0	0	GUID
PRONAME   	FUNCNAME	CHAR	30	0	0	函数名 
ERDAT	    ERDAT	DATS	8	0	0	记录创建日期
ERNAM	    ERNAM	CHAR	12	0	0	创建对象的人员名称 
UZEIT	    UZEIT	TIMS	6	0	0	时间
TYPE	    WER_MSG_TYPE	CHAR	1	0	0	消息类型
MSG      	UMK_Y_MESSAGE	CHAR	255	0	0	消息
PAYLOD		STRING	0	0	0	JSON
CUST_FIELD1	ZE_CUST_FIELD	CHAR	50	0	0	Custom Field
CUST_FIELD2	ZE_CUST_FIELD	CHAR	50	0	0	Custom Field
CUST_FIELD3	ZE_CUST_FIELD	CHAR	50	0	0	Custom Field

工具类

zcl_json_handler
CLASS zcl_json_handler DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES if_http_extension .

    TYPE-POOLS abap .
    CONSTANTS xnl TYPE abap_char1 VALUE %_newline.          "#EC NOTEXT
    CONSTANTS xcrlf TYPE abap_cr_lf VALUE %_cr_lf.          "#EC NOTEXT
    DATA my_service TYPE string .
    DATA my_url TYPE string .

    CLASS-METHODS abap2json
      IMPORTING
        !abap_data         TYPE data
        !name              TYPE string OPTIONAL
        !upcase            TYPE xfeld OPTIONAL
        !camelcase         TYPE xfeld OPTIONAL
      RETURNING
        VALUE(json_string) TYPE string
      EXCEPTIONS
        error_in_data_description .
    CLASS-METHODS abap2perl
      IMPORTING
        !abap_data         TYPE data
        !name              TYPE string OPTIONAL
        !upcase            TYPE xfeld OPTIONAL
      RETURNING
        VALUE(perl_string) TYPE string
      EXCEPTIONS
        error_in_data_description .
    CLASS-METHODS abap2xml
      IMPORTING
        !abap_data        TYPE data
        !name             TYPE string OPTIONAL
        !with_xml_header  TYPE abap_bool DEFAULT abap_false
        !upcase           TYPE xfeld OPTIONAL
        !name_atr         TYPE string OPTIONAL
      RETURNING
        VALUE(xml_string) TYPE string .
    CLASS-METHODS abap2yaml
      IMPORTING
        !abap_data         TYPE data
        !name              TYPE string OPTIONAL
        !upcase            TYPE xfeld OPTIONAL
        !y_level           TYPE i DEFAULT 0
        !s_index           TYPE i DEFAULT 0
        !first_row         TYPE xfeld OPTIONAL
        !dont_indent       TYPE xfeld OPTIONAL
      RETURNING
        VALUE(yaml_string) TYPE string
      EXCEPTIONS
        error_in_data_description .
    CLASS-METHODS build_params
      IMPORTING
        !function_name TYPE rs38l_fnam
      EXPORTING
        !paramtab      TYPE abap_func_parmbind_tab
        !exceptab      TYPE abap_func_excpbind_tab
        !params        TYPE any
      EXCEPTIONS
        invalid_function
        unsupported_param_type .
    TYPE-POOLS js .
    CLASS-METHODS json2abap
      IMPORTING
        !json_string    TYPE string OPTIONAL
        !var_name       TYPE string OPTIONAL
        !property_path  TYPE string DEFAULT 'json_obj'
      EXPORTING
        !property_table TYPE js_property_tab
      CHANGING
        !js_object      TYPE REF TO cl_java_script
        !abap_data      TYPE any OPTIONAL
      RAISING
        zcx_json .
    CLASS-METHODS json_deserialize
      IMPORTING
        !json     TYPE string
      CHANGING
        !paramtab TYPE abap_func_parmbind_tab
      EXCEPTIONS
        zcx_json .
    METHODS notes
      RETURNING
        VALUE(text) TYPE string .
    CLASS-METHODS serialize_json
      IMPORTING
        !paramtab  TYPE abap_func_parmbind_tab
        !params    TYPE any OPTIONAL
        !exceptab  TYPE abap_func_excpbind_tab OPTIONAL
        !show_impp TYPE abap_bool OPTIONAL
        !jsonp     TYPE string OPTIONAL
        !lowercase TYPE abap_bool DEFAULT abap_false
        !camelcase TYPE abap_bool DEFAULT abap_false
      EXPORTING
        !o_string  TYPE string .
    CLASS-METHODS serialize_perl
      IMPORTING
        !paramtab    TYPE abap_func_parmbind_tab
        !params      TYPE any OPTIONAL
        !exceptab    TYPE abap_func_excpbind_tab OPTIONAL
        !show_impp   TYPE abap_bool OPTIONAL
        !jsonp       TYPE string OPTIONAL
        !lowercase   TYPE abap_bool DEFAULT abap_false
        !funcname    TYPE rs38l_fnam
      EXPORTING
        !perl_string TYPE string .
    CLASS-METHODS serialize_xml
      IMPORTING
        !paramtab  TYPE abap_func_parmbind_tab
        !params    TYPE any OPTIONAL
        !exceptab  TYPE abap_func_excpbind_tab OPTIONAL
        !show_impp TYPE abap_bool OPTIONAL
        !jsonp     TYPE string OPTIONAL
        !funcname  TYPE rs38l_fnam
        !lowercase TYPE abap_bool DEFAULT abap_false
        !format    TYPE string
      EXPORTING
        !o_string  TYPE string .
    CLASS-METHODS serialize_yaml
      IMPORTING
        !paramtab    TYPE abap_func_parmbind_tab
        !params      TYPE any
        !exceptab    TYPE abap_func_excpbind_tab
        !show_impp   TYPE abap_bool
        !jsonp       TYPE string
        !lowercase   TYPE abap_bool DEFAULT abap_false
      EXPORTING
        !yaml_string TYPE string .
    CLASS-METHODS deserialize_id
      IMPORTING
        !json     TYPE string
      CHANGING
        !paramtab TYPE abap_func_parmbind_tab
      RAISING
        zcx_json .
    CLASS-METHODS serialize_id
      IMPORTING
        !paramtab  TYPE abap_func_parmbind_tab
        !params    TYPE any OPTIONAL
        !exceptab  TYPE abap_func_excpbind_tab OPTIONAL
        !show_impp TYPE abap_bool OPTIONAL
        !jsonp     TYPE string OPTIONAL
        !lowercase TYPE abap_bool DEFAULT abap_false
        !format    TYPE string DEFAULT 'JSON'
        !funcname  TYPE rs38l_fnam OPTIONAL
        !camelcase TYPE abap_bool DEFAULT abap_false
      EXPORTING
        !o_string  TYPE string
      RAISING
        zcx_json .
    CLASS-METHODS convert_json_datetime_to_abap
      IMPORTING
        !iv_timestamp TYPE string
      EXPORTING
        !ev_date      TYPE sydate
        !ev_time      TYPE syuzeit
        !ev_msec      TYPE num03 .
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zcl_json_handler IMPLEMENTATION.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>ABAP2JSON
* +-------------------------------------------------------------------------------------------------+
* | [--->] ABAP_DATA                      TYPE        DATA
* | [--->] NAME                           TYPE        STRING(optional)
* | [--->] UPCASE                         TYPE        XFELD(optional)
* | [--->] CAMELCASE                      TYPE        XFELD(optional)
* | [<-()] JSON_STRING                    TYPE        STRING
* | [EXC!] ERROR_IN_DATA_DESCRIPTION
* +--------------------------------------------------------------------------------------
  METHOD abap2json.
*/**********************************************/*
*/ This method takes any ABAP data variable and /*
*/ returns a string representing its value in   /*
*/ JSON format.                                 /*
*/ ABAP references are always de-referenced and /*
*/ treated as normal variables.                 /*
*/**********************************************/*

    TYPE-POOLS: abap.

    CONSTANTS:
      c_comma TYPE c VALUE ',',
      c_colon TYPE c VALUE ':',
      c_quote TYPE c VALUE '"'.

    DATA:
      dont_quote      TYPE xfeld,
      json_fragments  TYPE TABLE OF string,
      rec_json_string TYPE string,
      l_type          TYPE c,
      s_type          TYPE c,
      l_comps         TYPE i,
      l_lines         TYPE i,
      l_index         TYPE i,
      l_value         TYPE string,
      l_name          TYPE string,
      l_strudescr     TYPE REF TO cl_abap_structdescr.

    FIELD-SYMBOLS:
       TYPE any,
            TYPE ANY TABLE,
            TYPE ANY TABLE,
            TYPE any,
        TYPE abap_compdescr.


    DEFINE get_scalar_value.
      " &1 : assigned var
      " &2 : abap data
      " &3 : abap type
      &1 = &2.
****************************************************
* Adapt some basic ABAP types (pending inclusion of all basic abap types?)
* Feel free to customize this for your needs
      CASE &3.
*       1. ABAP numeric types
        WHEN 'I'. " Integer
          CONDENSE &1.
          IF sign( &1 ) < 0.
            SHIFT &1 BY 1 PLACES RIGHT CIRCULAR.
          ENDIF.
          dont_quote = 'X'.

        WHEN 'F'. " Float
          CONDENSE &1.
          dont_quote = 'X'.

        WHEN 'P'. " Packed number (used in quantities or currency, for example)
          CONDENSE &1.
          IF sign( &1 ) < 0.
            SHIFT &1 BY 1 PLACES RIGHT CIRCULAR.
          ENDIF.
          dont_quote = 'X'.

        WHEN 'X'. " Hexadecimal
          CONDENSE &1.
          CONCATENATE '0x' &1 INTO &1.
*        dont_quote = 'X'.
*        "Quote it, as JSON doesn't support Hex or Octal as native types.

*       2. ABAP char types
        WHEN 'D'. " Date type
          CONCATENATE &1(4) '-' &1+4(2) '-' &1+6(2) INTO &1.

        WHEN 'T'. " Time representation
          CONCATENATE &1(2) ':' &1+2(2) ':' &1+4(2) INTO &1.

        WHEN 'N'. " Numeric text field
*           condense &1.

        WHEN 'C' OR 'g'. " Char sequences and Strings
* Put safe chars
          REPLACE ALL OCCURRENCES OF '\' IN &1 WITH '\\' .
          REPLACE ALL OCCURRENCES OF '"' IN &1 WITH '\"' .
          REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN &1 WITH '\r\n' .
          REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline IN &1 WITH '\n' .
          REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>horizontal_tab IN &1 WITH '\t' .
          REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>backspace IN &1 WITH '\b' .
          REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>form_feed IN &1 WITH '\f' .

        WHEN 'y'.  " XSTRING
* Put the XSTRING in Base64
          &1 = cl_http_utility=>encode_x_base64( &2 ).

        WHEN OTHERS.
* Don't hesitate to add and modify scalar abap types to suit your taste.

      ENDCASE.
** End of scalar data preparing.

* Enclose value in quotes (or not)
      IF dont_quote NE 'X'.
        CONCATENATE c_quote &1 c_quote INTO &1.
      ENDIF.

      CLEAR dont_quote.

    end-of-definition.


***************************************************
*  Prepare field names, JSON does quote names!!   *
*  You must be strict in what you produce.        *
***************************************************
    IF name IS NOT INITIAL.
      CONCATENATE c_quote name c_quote c_colon INTO rec_json_string.
      APPEND rec_json_string TO json_fragments.
      CLEAR rec_json_string.
    ENDIF.

**
* Get ABAP data type
    DESCRIBE FIELD abap_data TYPE l_type COMPONENTS l_comps.

***************************************************
*  Get rid of data references
***************************************************
    IF l_type EQ cl_abap_typedescr=>typekind_dref.
      ASSIGN abap_data->* TO .
      IF sy-subrc NE 0.
        APPEND '{}' TO json_fragments.
        CONCATENATE LINES OF json_fragments INTO json_string.
        EXIT.
      ENDIF.
    ELSE.
      ASSIGN abap_data TO .
    ENDIF.

* Get ABAP data type again and start
    DESCRIBE FIELD  TYPE l_type COMPONENTS l_comps.

***************************************************
*  Tables
***************************************************
    IF l_type EQ cl_abap_typedescr=>typekind_table.
* '[' JSON table opening bracket
      APPEND '[' TO json_fragments.
      ASSIGN  TO .
      l_lines = lines(  ).
      LOOP AT  ASSIGNING .
        ADD 1 TO l_index.
*> Recursive call for each table row:
        rec_json_string = abap2json( abap_data =  upcase = upcase camelcase = camelcase ).
        APPEND rec_json_string TO json_fragments.
        CLEAR rec_json_string.
        IF l_index < l_lines.
          APPEND c_comma TO json_fragments.
        ENDIF.
      ENDLOOP.
      APPEND ']' TO json_fragments.
* ']' JSON table closing bracket


***************************************************
*  Structures
***************************************************
    ELSE.
      IF l_comps IS NOT INITIAL.
* '{' JSON object opening curly brace
        APPEND '{' TO json_fragments.
        l_strudescr ?= cl_abap_typedescr=>describe_by_data(  ).
        LOOP AT l_strudescr->components ASSIGNING .
          l_index = sy-tabix .
          ASSIGN COMPONENT -name OF STRUCTURE  TO .
          l_name = -name.
** ABAP names are usually in caps, set upcase to avoid the conversion to lower case.
          IF upcase NE 'X'.
            " translate l_name to lower case.
            l_name = to_lower( l_name ).
          ENDIF.
          IF camelcase EQ 'X'.
            DATA:lv_name1 TYPE char50.
            lv_name1 = l_name.
            lv_name1 = to_mixed( val = l_name  case = 'A' ).
            l_name = to_lower( lv_name1 ).
          ENDIF.
          DESCRIBE FIELD  TYPE s_type.
          IF s_type EQ cl_abap_typedescr=>typekind_table OR s_type EQ cl_abap_typedescr=>typekind_dref OR
             s_type EQ cl_abap_typedescr=>typekind_struct1 OR s_type EQ cl_abap_typedescr=>typekind_struct2.
*> Recursive call for non-scalars:
            rec_json_string = abap2json( abap_data =  name = l_name upcase = upcase camelcase = camelcase ).
          ELSE.
            IF s_type EQ cl_abap_typedescr=>typekind_oref OR s_type EQ cl_abap_typedescr=>typekind_iref.
              rec_json_string = '"REF UNSUPPORTED"'.
            ELSE.
              get_scalar_value rec_json_string  s_type.
            ENDIF.
            CONCATENATE c_quote l_name c_quote c_colon rec_json_string INTO rec_json_string.
          ENDIF.
          APPEND rec_json_string TO json_fragments.
          CLEAR rec_json_string. CLEAR l_name.
          IF l_index < l_comps.
            APPEND c_comma TO json_fragments.
          ENDIF.
        ENDLOOP.
        APPEND '}' TO json_fragments.
* '}' JSON object closing curly brace


****************************************************
*                  - Scalars -                     *
****************************************************
      ELSE.
        get_scalar_value l_value  l_type.
        APPEND l_value TO json_fragments.

      ENDIF.
* End of structure/scalar IF block.
***********************************

    ENDIF.
* End of main IF block.
**********************

* Use a loop in older releases that don't support concatenate lines.
    CONCATENATE LINES OF json_fragments INTO json_string.

  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>ABAP2PERL
* +-------------------------------------------------------------------------------------------------+
* | [--->] ABAP_DATA                      TYPE        DATA
* | [--->] NAME                           TYPE        STRING(optional)
* | [--->] UPCASE                         TYPE        XFELD(optional)
* | [<-()] PERL_STRING                    TYPE        STRING
* | [EXC!] ERROR_IN_DATA_DESCRIPTION
* +--------------------------------------------------------------------------------------
  METHOD abap2perl.
*/**********************************************/*
*/ This method takes any ABAP data variable and /*
*/ returns a string representing its value in   /*
*/ Perl Data::Dumper format, ready to be evaled /*
*/ in a Perl program.                           /*
*/**********************************************/*

    TYPE-POOLS: abap.

    CONSTANTS:
      c_comma TYPE c VALUE ',',
      c_colon TYPE c VALUE ':',
      c_quote TYPE c VALUE ''''.

    DATA:
      perl_hash_assign TYPE string,
      dont_quote       TYPE xfeld,
      perl_fragments   TYPE TABLE OF string,
      rec_perl_string  TYPE string,
      l_type           TYPE c,
      s_type           TYPE c,
      l_comps          TYPE i,
      l_lines          TYPE i,
      l_index          TYPE i,
      l_value          TYPE string,
      l_name           TYPE string,
      l_typedescr      TYPE REF TO cl_abap_structdescr.

    FIELD-SYMBOLS:
       TYPE any,
            TYPE ANY TABLE,
            TYPE ANY TABLE,
            TYPE any,
        TYPE abap_compdescr.

    CONCATENATE space '=>' space INTO perl_hash_assign RESPECTING BLANKS.

    DEFINE get_scalar_value.
      " &1 : assigned var
      " &2 : abap data
      " &3 : abap type
      &1 = &2.
****************************************************
* Adapt some basic ABAP types (pending inclusion of all basic abap types?)
* Feel free to customize this for your needs
      CASE &3.
*       1. ABAP numeric types
        WHEN 'I'. " Integer
          CONDENSE &1.
          IF sign( &1 ) < 0.
            SHIFT &1 BY 1 PLACES RIGHT CIRCULAR.
          ENDIF.
          dont_quote = 'X'.

        WHEN 'F'. " Float
          CONDENSE &1.
          dont_quote = 'X'.

        WHEN 'P'. " Packed number (used in quantities, for example)
          CONDENSE &1.
          IF sign( &1 ) < 0.
            SHIFT &1 BY 1 PLACES RIGHT CIRCULAR.
          ENDIF.
          dont_quote = 'X'.

        WHEN 'X'. " Hexadecimal
          CONDENSE &1.
          CONCATENATE '0x' &1 INTO &1.
          dont_quote = 'X'.

*       2. ABAP char types
        WHEN 'D'. " Date type
          CONCATENATE &1(4) '-' &1+4(2) '-' &1+6(2) INTO &1.

        WHEN 'T'. " Time representation
          CONCATENATE &1(2) ':' &1+2(2) ':' &1+4(2) INTO &1.

        WHEN 'N'. " Numeric text field
*           condense &1.

        WHEN 'C' OR 'g'. " Char sequences and Strings
* Put safe chars
          REPLACE ALL OCCURRENCES OF '''' IN &1 WITH '\''' .

        WHEN 'y'.  " XSTRING
* Put the XSTRING in Base64
          &1 = cl_http_utility=>encode_x_base64( &2 ).

        WHEN OTHERS.
* Don't hesitate to add and modify abap types to suit your taste.

      ENDCASE.
** End of scalar data preparing.

* Enclose value in quotes (or not)
      IF dont_quote NE 'X'.
        CONCATENATE c_quote &1 c_quote INTO &1.
      ENDIF.
      CLEAR dont_quote.

    end-of-definition.



***************************************************
*  Prepare field names, we use single quotes.     *
*  You must be strict in what you produce.        *
***************************************************
    IF name IS NOT INITIAL.
      CONCATENATE c_quote name c_quote perl_hash_assign INTO rec_perl_string RESPECTING BLANKS.
      APPEND rec_perl_string TO perl_fragments.
      CLEAR rec_perl_string.
    ENDIF.

**
* Get ABAP data type
    DESCRIBE FIELD abap_data TYPE l_type COMPONENTS l_comps.

***************************************************
*  Get rid of data references
***************************************************
    IF l_type EQ cl_abap_typedescr=>typekind_dref.
      ASSIGN abap_data->* TO .
      IF sy-subrc NE 0.
        APPEND '{}' TO perl_fragments.
        CONCATENATE LINES OF perl_fragments INTO perl_string.
        EXIT.
      ENDIF.
    ELSE.
      ASSIGN abap_data TO .
    ENDIF.


* Get ABAP data type again and start
    DESCRIBE FIELD  TYPE l_type COMPONENTS l_comps.

***************************************************
*  Tables
***************************************************
    IF l_type EQ cl_abap_typedescr=>typekind_table.
* '[' Table opening bracket
      APPEND '[' TO perl_fragments.
      ASSIGN  TO .
      l_lines = lines(  ).
      LOOP AT  ASSIGNING .
        ADD 1 TO l_index.
*> Recursive call here
        rec_perl_string = abap2perl( abap_data =  upcase = upcase ).
        APPEND rec_perl_string TO perl_fragments.
        CLEAR rec_perl_string.
        IF l_index < l_lines.
          APPEND c_comma TO perl_fragments.
        ENDIF.
      ENDLOOP.
      APPEND ']' TO perl_fragments.
* ']' Table closing bracket


***************************************************
*  Structures
***************************************************
    ELSE .
      IF l_comps IS NOT INITIAL.
* '{' Object opening curly brace
        APPEND '{' TO perl_fragments .
        l_typedescr ?= cl_abap_typedescr=>describe_by_data(  ) .
        LOOP AT l_typedescr->components ASSIGNING  .
          l_index = sy-tabix .
          ASSIGN COMPONENT -name OF STRUCTURE  TO .
          l_name = -name.
** ABAP names are usually in caps, set upcase to avoid the conversion to lower case.
          IF upcase NE 'X'.
            TRANSLATE l_name TO LOWER CASE.
          ENDIF.
          DESCRIBE FIELD  TYPE s_type.
          IF s_type EQ cl_abap_typedescr=>typekind_table OR s_type EQ cl_abap_typedescr=>typekind_dref OR
             s_type EQ cl_abap_typedescr=>typekind_struct1 OR s_type EQ cl_abap_typedescr=>typekind_struct2.
*> Recursive call for non-scalars:
            rec_perl_string = abap2perl( abap_data =  name = l_name upcase = upcase ).
          ELSE.
            IF s_type EQ cl_abap_typedescr=>typekind_oref OR s_type EQ cl_abap_typedescr=>typekind_iref.
              rec_perl_string = '"REF UNSUPPORTED"'.
            ELSE.
              get_scalar_value rec_perl_string  s_type.
            ENDIF.
            CONCATENATE c_quote l_name c_quote perl_hash_assign rec_perl_string INTO rec_perl_string.
          ENDIF.

          APPEND rec_perl_string TO perl_fragments.
          CLEAR rec_perl_string.
          IF l_index < l_comps.
            APPEND c_comma TO perl_fragments.
          ENDIF.
        ENDLOOP.
        APPEND '}' TO perl_fragments.
* '}' Object closing curly brace


****************************************************
*                  - Scalars -                     *
****************************************************
      ELSE.

        get_scalar_value l_value  l_type.
        APPEND l_value TO perl_fragments.

      ENDIF.
* End of structure/scalar IF block.
***********************************


    ENDIF.
* End of main IF block.
**********************


* Use a loop in older releases that don't support concatenate lines.
    CONCATENATE LINES OF perl_fragments INTO perl_string.

  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>ABAP2XML
* +-------------------------------------------------------------------------------------------------+
* | [--->] ABAP_DATA                      TYPE        DATA
* | [--->] NAME                           TYPE        STRING(optional)
* | [--->] WITH_XML_HEADER                TYPE        ABAP_BOOL (default =ABAP_FALSE)
* | [--->] UPCASE                         TYPE        XFELD(optional)
* | [--->] NAME_ATR                       TYPE        STRING(optional)
* | [<-()] XML_STRING                     TYPE        STRING
* +--------------------------------------------------------------------------------------
  METHOD abap2xml.
*
*/ Look at method serialize_id for a new way of doing XML.

    TYPE-POOLS: abap.

    CONSTANTS:
      xml_head TYPE string VALUE '',
      item_atr TYPE string VALUE 'idx="#"'.

    DATA:
      xml_fragments  TYPE TABLE OF string,
      rec_xml_string TYPE string,
      l_type         TYPE c,
      s_type         TYPE c,
      l_comps        TYPE i,
      l_value        TYPE string,
      t_string       TYPE string,
      l_item_atr     TYPE string,
      l_item_str     TYPE string,
      l_name         TYPE string,
      l_idx          TYPE string,
      l_typedescr    TYPE REF TO cl_abap_structdescr,
      l_linedescr    TYPE REF TO cl_abap_datadescr,
      l_tabledescr   TYPE REF TO cl_abap_tabledescr.

    FIELD-SYMBOLS:
       TYPE any,
            TYPE ANY TABLE,
            TYPE ANY TABLE,
            TYPE any,
        TYPE abap_compdescr.

    DEFINE get_scalar_value.
      " &1 : assigned var
      " &2 : abap data
      " &3 : abap type
      &1 = &2.
****************************************************
* Adapt some basic ABAP types (pending inclusion of all basic abap types?)
* Feel free to customize this for your needs
      CASE &3.
*       1. ABAP numeric types
        WHEN 'I'. " Integer
          CONDENSE &1.
          IF sign( &1 ) < 0.
            SHIFT &1 BY 1 PLACES RIGHT CIRCULAR.
          ENDIF.

        WHEN 'F'. " Float
          CONDENSE &1.

        WHEN 'P'. " Packed number (used in quantities, for example)
          CONDENSE &1.
          IF sign( &1 ) < 0.
            SHIFT &1 BY 1 PLACES RIGHT CIRCULAR.
          ENDIF.

        WHEN 'X'. " Hexadecimal
          CONDENSE &1.
          CONCATENATE '0x' &1 INTO &1.

*       2. ABAP char types
        WHEN 'D'. " Date type
          CONCATENATE &1(4) '-' &1+4(2) '-' &1+6(2) INTO &1.

        WHEN 'T'. " Time representation
          CONCATENATE &1(2) ':' &1+2(2) ':' &1+4(2) INTO &1.

        WHEN 'N'. " Numeric text field
*           condense &1.

        WHEN 'C' OR 'g'. " Char sequences and Strings
* Put safe chars
          t_string = &2.
          &1 = cl_http_utility=>escape_html( t_string ).

        WHEN 'y'.  " XSTRING
* Put the XSTRING in Base64
          &1 = cl_http_utility=>encode_x_base64( &2 ).

        WHEN OTHERS.
* Don't hesitate to add and modify abap types to suit your taste.

      ENDCASE.
** End of scalar data preparing.

    end-of-definition.



*******************************
* Put XML header if requested *
*******************************
    IF with_xml_header EQ abap_true.
      APPEND xml_head TO xml_fragments.
    ENDIF.

***************************************************
*  Open XML tag                                   *
*  <          >                                   *
***************************************************
    IF name IS NOT INITIAL.
      l_name = name.
      IF name_atr IS NOT INITIAL.
        CONCATENATE name name_atr INTO l_name SEPARATED BY space.
      ENDIF.
      CONCATENATE '<' l_name '>' INTO rec_xml_string.
      APPEND rec_xml_string TO xml_fragments.
      CLEAR rec_xml_string.
    ENDIF.

**
* Get ABAP data type
    DESCRIBE FIELD abap_data TYPE l_type COMPONENTS l_comps .

***************************************************
*  Get rid of data references
***************************************************
    IF l_type EQ cl_abap_typedescr=>typekind_dref.
      ASSIGN abap_data->* TO .
      IF sy-subrc NE 0.
        IF name IS NOT INITIAL.
          CONCATENATE '<' name '/>' INTO xml_string.
        ELSE.
          CLEAR xml_string.
        ENDIF.
        EXIT.
      ENDIF.
    ELSE.
      ASSIGN abap_data TO .
    ENDIF.


* Get ABAP data type again and start
    DESCRIBE FIELD  TYPE l_type COMPONENTS l_comps.


***************************************************
*  Tables
***************************************************
    IF l_type EQ cl_abap_typedescr=>typekind_table.
      l_tabledescr ?= cl_abap_typedescr=>describe_by_data(  ).
      l_linedescr = l_tabledescr->get_table_line_type( ).
      l_item_str = l_linedescr->get_relative_name( ).
      ASSIGN  TO .
      LOOP AT  ASSIGNING .
        l_idx = sy-tabix.
        CONDENSE l_idx.
        l_item_atr = item_atr.
        REPLACE '#' IN l_item_atr WITH l_idx.
        IF upcase NE 'X'.
          TRANSLATE l_item_str TO LOWER CASE.
        ENDIF.
*> Recursive call for line items here:
        rec_xml_string = abap2xml( abap_data =  upcase = upcase name = l_item_str name_atr = l_item_atr ).
        APPEND rec_xml_string TO xml_fragments.
        CLEAR rec_xml_string.
      ENDLOOP.


***************************************************
*  Structures
***************************************************
    ELSE .
      IF l_comps IS NOT INITIAL.
        l_typedescr ?= cl_abap_typedescr=>describe_by_data(  ).
        LOOP AT l_typedescr->components ASSIGNING  .
          ASSIGN COMPONENT -name OF STRUCTURE  TO .
          l_name = -name. " l_value justs holds the name here.
** ABAP names are usually in caps, set upcase to avoid the conversion to lower case.
          IF upcase NE 'X'.
            TRANSLATE l_name TO LOWER CASE.
          ENDIF.
          DESCRIBE FIELD  TYPE s_type.
          IF s_type EQ cl_abap_typedescr=>typekind_table OR s_type EQ cl_abap_typedescr=>typekind_dref OR
             s_type EQ cl_abap_typedescr=>typekind_struct1 OR s_type EQ cl_abap_typedescr=>typekind_struct2.
*> Recursive call for non-scalars:
            rec_xml_string = abap2xml( abap_data =  name = l_name upcase = upcase ).
          ELSE.
            IF s_type EQ cl_abap_typedescr=>typekind_oref OR s_type EQ cl_abap_typedescr=>typekind_iref.
              rec_xml_string = 'REF UNSUPPORTED'.
            ELSE.
              get_scalar_value rec_xml_string  s_type.
            ENDIF.
            CONCATENATE '<' l_name '>' rec_xml_string '' INTO rec_xml_string.
          ENDIF.
          APPEND rec_xml_string TO xml_fragments.
          CLEAR rec_xml_string.
        ENDLOOP.



****************************************************
*                  - Scalars -                     *
****************************************************
      ELSE.

        get_scalar_value l_value  l_type.
        APPEND l_value TO xml_fragments.

      ENDIF.
* End of structure/scalar IF block.
***********************************


    ENDIF.
* End of main IF block.
**********************


*****************
* Close XML tag *
*****************
    IF name IS NOT INITIAL.
      CONCATENATE '' INTO rec_xml_string.
      APPEND rec_xml_string TO xml_fragments.
      CLEAR rec_xml_string.
    ENDIF.

* Use a loop in older releases that don't support concatenate lines.
    CONCATENATE LINES OF xml_fragments INTO xml_string.

  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>ABAP2YAML
* +-------------------------------------------------------------------------------------------------+
* | [--->] ABAP_DATA                      TYPE        DATA
* | [--->] NAME                           TYPE        STRING(optional)
* | [--->] UPCASE                         TYPE        XFELD(optional)
* | [--->] Y_LEVEL                        TYPE        I (default =0)
* | [--->] S_INDEX                        TYPE        I (default =0)
* | [--->] FIRST_ROW                      TYPE        XFELD(optional)
* | [--->] DONT_INDENT                    TYPE        XFELD(optional)
* | [<-()] YAML_STRING                    TYPE        STRING
* | [EXC!] ERROR_IN_DATA_DESCRIPTION
* +--------------------------------------------------------------------------------------
  METHOD abap2yaml.
*********************
* ABAP goes to YAML *
*********************

    TYPE-POOLS: abap.

    CONSTANTS:
      c_comma    TYPE c VALUE ',',
      c_space    TYPE c VALUE ' ',
      c_colon    TYPE c VALUE ':',
      c_quote    TYPE c VALUE '"',
      c_squot    TYPE c VALUE '''',
      c_colo2(2) TYPE c VALUE ': ',
      c_indt2    TYPE i VALUE 2,
      c_hyph     TYPE c VALUE '-'.

    DATA:
      ly_level        TYPE i,
      l_dont_indent   TYPE xfeld,
      dec_level       TYPE i VALUE 0,
      dont_quote      TYPE xfeld,
      yaml_fragments  TYPE TABLE OF string,
      rec_yaml_string TYPE string,
      l_type          TYPE c,
      l_comps         TYPE i,
      l_lines         TYPE i,
      l_index         TYPE i,
      l_value         TYPE string,
      l_name          TYPE string.
    FIELD-SYMBOLS:
       TYPE any,
            TYPE ANY TABLE,
            TYPE ANY TABLE,
            TYPE any.
    DATA l_typedescr TYPE REF TO cl_abap_structdescr .
    FIELD-SYMBOLS  TYPE abap_compdescr .

    ly_level = y_level.

**
* Get ABAP data type
    DESCRIBE FIELD abap_data TYPE l_type COMPONENTS l_comps .

***************************************************
*  First of all, get rid of data references
***************************************************
    IF l_type EQ cl_abap_typedescr=>typekind_dref.
      ASSIGN abap_data->* TO .
      IF sy-subrc NE 0.
        yaml_string = space. " pasamos de poner nada si falla...
        EXIT.
      ENDIF.
    ELSE.
      ASSIGN abap_data TO .
    ENDIF.


* Get ABAP data type again and start
    DESCRIBE FIELD  TYPE l_type COMPONENTS l_comps.

***************************************************
*  Prepare field names, YAML does not quote names *
***************************************************
* Put hyphens...
    IF name IS INITIAL AND y_level GT 0.
      CONCATENATE c_hyph space INTO rec_yaml_string RESPECTING BLANKS.
      l_dont_indent = 'X'.
    ENDIF.

    IF name IS NOT INITIAL.
      CONCATENATE name c_colon c_space INTO rec_yaml_string RESPECTING BLANKS.
    ENDIF.

* do indent
    IF dont_indent NE 'X'.
      DO  ly_level  TIMES.
        SHIFT rec_yaml_string RIGHT BY c_indt2 PLACES.
      ENDDO.
    ENDIF.

    APPEND rec_yaml_string TO yaml_fragments.
    CLEAR rec_yaml_string.




***************************************************
*  Tables
***************************************************
    IF l_type EQ cl_abap_typedescr=>typekind_table.
      ASSIGN  TO .
      l_lines = lines(  ).
      CLEAR l_index.
      IF l_lines EQ 0.
        MOVE '[]' TO rec_yaml_string.
        APPEND rec_yaml_string TO yaml_fragments.
        CLEAR rec_yaml_string.
        APPEND xnl TO yaml_fragments.
      ELSE.
        IF name IS NOT INITIAL.
          APPEND xnl TO yaml_fragments.
        ENDIF.
        ADD 1 TO ly_level.
        LOOP AT  ASSIGNING .
          ADD 1 TO l_index.
*> Recursive call here
          rec_yaml_string = abap2yaml( abap_data =  upcase = upcase y_level = ly_level s_index = l_index ).
          APPEND rec_yaml_string TO yaml_fragments.
          CLEAR rec_yaml_string.
        ENDLOOP.
      ENDIF.
* YAML table ends *
*******************


***************************************************
*  Structures
***************************************************
    ELSE .
      IF l_comps IS NOT INITIAL.
        IF name IS NOT INITIAL.
          APPEND xnl TO yaml_fragments.
        ENDIF.
        ADD 1 TO ly_level.
* Loop for structure elements
        l_typedescr ?= cl_abap_typedescr=>describe_by_data(  ) .
        CLEAR l_index.
        LOOP AT l_typedescr->components ASSIGNING .
          ADD 1 TO l_index.
          ASSIGN COMPONENT -name OF STRUCTURE  TO .
          l_name = -name.
** ABAP names are usually in caps, set upcase to avoid the conversion to lower case.
          IF upcase NE 'X'.
            TRANSLATE l_name TO LOWER CASE.
          ENDIF.
*> Recursive call here
          rec_yaml_string = abap2yaml( abap_data =  name = l_name upcase = upcase y_level = ly_level s_index = l_index dont_indent = l_dont_indent ).
          CLEAR l_dont_indent. " it is only used once
          APPEND rec_yaml_string TO yaml_fragments.
          CLEAR rec_yaml_string.
        ENDLOOP.

* YAML structure ends *
***********************


***************************************************
*  Scalars and others...
***************************************************
      ELSE.
        IF l_type EQ cl_abap_typedescr=>typekind_oref OR l_type EQ cl_abap_typedescr=>typekind_iref.
          l_value = 'REF UNSUPPORTED'.
        ELSE.
          l_value = .
        ENDIF.

* Adapt some basic ABAP types (pending inclusion of all basic abap types)
* Feel free to customize this for your needs
        CASE l_type.
*       1. ABAP numeric types
          WHEN 'I'. " Integer
            CONDENSE l_value.
            IF sign( l_value ) < 0.
              SHIFT l_value BY 1 PLACES RIGHT CIRCULAR.
            ENDIF.
            dont_quote = 'X'.

          WHEN 'F'. " Float
            CONDENSE l_value.
            dont_quote = 'X'.

          WHEN 'P'. " Packed number (used in quantities, for example)
            CONDENSE l_value.
            IF sign( l_value ) < 0.
              SHIFT l_value BY 1 PLACES RIGHT CIRCULAR.
            ENDIF.
            dont_quote = 'X'.

          WHEN 'X'. " Hexadecimal
            CONDENSE l_value.
            CONCATENATE '0x' l_value INTO l_value.
            dont_quote = 'X'.

*       2. ABAP char types
          WHEN 'D'. " Date type
            CONCATENATE l_value(4) '-' l_value+4(2) '-' l_value+6(2) INTO l_value.

          WHEN 'T'. " Time representation
            CONCATENATE l_value(2) ':' l_value+2(2) ':' l_value+4(2) INTO l_value.

          WHEN 'N'. " Numeric text field
*           condense l_value.

          WHEN 'C' OR 'g'. " Chars and Strings
* Put safe chars
            REPLACE ALL OCCURRENCES OF '\' IN l_value WITH '\\' .
            REPLACE ALL OCCURRENCES OF '"' IN l_value WITH '\"' .
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN l_value WITH '\r\n' .
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline IN l_value WITH '\n' .
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>horizontal_tab IN l_value WITH '\t' .
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>backspace IN l_value WITH '\b' .
            REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>form_feed IN l_value WITH '\f' .

          WHEN 'y'.  " XSTRING
* Put the XSTRING in Base64
*          l_value = cl_http_utility=>ENCODE_X_BASE64(  ).
            l_value = 'XSTRING not supported in YAML yet!'.

          WHEN OTHERS.
* Don't hesitate to add and modify abap types to suit your taste.

        ENDCASE.

* We use YAML scalars double quoted
        IF dont_quote NE 'X'.
          CONCATENATE c_quote l_value c_quote INTO l_value.
        ELSE.
          CLEAR dont_quote.
        ENDIF.

        APPEND l_value TO yaml_fragments.

        APPEND xnl TO yaml_fragments.

      ENDIF. " is structure or scalar

    ENDIF. " main typekind sentence



* Use a loop in older releases that don't support concatenate lines.
    CONCATENATE LINES OF yaml_fragments INTO yaml_string RESPECTING BLANKS.

  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>BUILD_PARAMS
* +-------------------------------------------------------------------------------------------------+
* | [--->] FUNCTION_NAME                  TYPE        RS38L_FNAM
* | [<---] PARAMTAB                       TYPE        ABAP_FUNC_PARMBIND_TAB
* | [<---] EXCEPTAB                       TYPE        ABAP_FUNC_EXCPBIND_TAB
* | [<---] PARAMS                         TYPE        ANY
* | [EXC!] INVALID_FUNCTION
* | [EXC!] UNSUPPORTED_PARAM_TYPE
* +--------------------------------------------------------------------------------------
  METHOD build_params.

    TYPE-POOLS: abap.

    DATA defval TYPE rs38l_defo.
    DATA dataname TYPE string.
    DATA waref TYPE REF TO data.

    FIELD-SYMBOLS:
         TYPE any,
       TYPE any.

    DATA len TYPE i.
    DATA excnt TYPE i VALUE 1.

    DATA paramline  TYPE LINE  OF abap_func_parmbind_tab.
    DATA exceptline TYPE LINE  OF abap_func_excpbind_tab.
    DATA t_params_p TYPE TABLE OF rfc_fint_p.
    DATA params_p   TYPE rfc_fint_p.

    DEFINE remove_enclosing_quotes.
      " Remove enclosing single quotes
      IF &2 GT 1.
        SUBTRACT 1 FROM &2.
        IF &1+&2 EQ ''''.
          &1+&2 = space.
        ENDIF.
        IF &1(1) EQ ''''.
          SHIFT &1 LEFT.
        ENDIF.
        &2 = strlen( &1 ).
      ENDIF.
    end-of-definition.


* do we have the rfc name?
    CALL FUNCTION 'RFC_GET_FUNCTION_INTERFACE_P'
      EXPORTING
        funcname      = function_name
        language      = 'E'       "'D'  "sy-langu
      TABLES
        params_p      = t_params_p
      EXCEPTIONS
        fu_not_found  = 1
        nametab_fault = 2
        OTHERS        = 3.

    IF sy-subrc <> 0.
      RAISE invalid_function.
    ENDIF.


* Build params table
    LOOP AT t_params_p INTO params_p.

      UNASSIGN .
      UNASSIGN .
      CLEAR paramline.

      CASE params_p-paramclass.

        WHEN 'I' OR 'E' OR 'C'.

          paramline-name = params_p-parameter.

          IF params_p-paramclass = 'E'.
            paramline-kind = abap_func_importing.
          ELSEIF params_p-paramclass = 'I'.
            paramline-kind = abap_func_exporting.
          ELSE.
            paramline-kind = abap_func_changing.
          ENDIF.

          IF params_p-fieldname IS INITIAL.
            dataname = params_p-tabname.
          ELSE.
            CONCATENATE params_p-tabname params_p-fieldname INTO
                dataname SEPARATED BY '-'.
          ENDIF.

* Assign default values
          defval = params_p-default.
          IF dataname IS INITIAL.
            dataname = 'STRING'.  " use a STRING for this cases (see CONVERT_DATE_TO_EXTERNAL).
          ENDIF.
          CREATE DATA waref TYPE (dataname).
          ASSIGN waref->* TO .
          len = strlen( defval ).
          remove_enclosing_quotes defval len.
          IF defval = 'SPACE'.
             = space.
          ELSEIF len > 3 AND defval+0(3) = 'SY-'.
            ASSIGN (defval) TO .
             = .
            UNASSIGN .
          ELSE.
            IF defval IS NOT INITIAL.
               = defval.
            ENDIF.
          ENDIF.
          UNASSIGN .
          paramline-value = waref.
          INSERT paramline INTO TABLE paramtab.

        WHEN 'T'.
          paramline-name = params_p-parameter.
          paramline-kind = abap_func_tables.
          IF params_p-exid EQ 'h'.
            CREATE DATA waref TYPE (params_p-tabname).
          ELSE.
            CREATE DATA waref TYPE STANDARD TABLE OF (params_p-tabname).
          ENDIF.
          paramline-value = waref.
          INSERT paramline INTO TABLE paramtab.

        WHEN 'X'.
          exceptline-name = params_p-parameter.
          exceptline-value = excnt.
          DATA messg TYPE REF TO data.
          CREATE DATA messg TYPE string.
          ASSIGN messg->* TO .
           = params_p-paramtext.
          exceptline-message = messg.
          INSERT exceptline INTO TABLE exceptab.
          ADD 1 TO excnt.

        WHEN OTHERS.
          RAISE unsupported_param_type.

      ENDCASE.

    ENDLOOP.


* add in the catch all exception
    exceptline-name = 'OTHERS'.
    exceptline-value = excnt.
    INSERT exceptline INTO TABLE exceptab.


* return
    params = t_params_p.

*********************************
******* Remaining from 2006 *****
******* end of build_params *****
*********************************
  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>CONVERT_JSON_DATETIME_TO_ABAP
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_TIMESTAMP                   TYPE        STRING
* | [<---] EV_DATE                        TYPE        SYDATE
* | [<---] EV_TIME                        TYPE        SYUZEIT
* | [<---] EV_MSEC                        TYPE        NUM03
* +--------------------------------------------------------------------------------------
  METHOD convert_json_datetime_to_abap.
    DATA:
      lv_date      TYPE sy-datum,
      lv_days_i    TYPE i,
      lv_sec_i     TYPE i,
      lv_timestamp TYPE timestampl,
      lv_timsmsec  TYPE timestampl.
    CONSTANTS:
      lc_day_in_sec TYPE i VALUE 86400.
    CHECK iv_timestamp IS NOT INITIAL.
* IV_TIMESTAMP stores milliseconds since January 1, 1970, 00:00:00 GMT
    lv_timestamp = iv_timestamp / 1000.   "timestamp in seconds
* One day has 86400 seconds: Timestamp in days
    lv_days_i    = lv_timestamp DIV lc_day_in_sec.
    lv_date      = '19700101'.
    ev_date     = lv_date + lv_days_i.
* Rest seconds (timestamp - days)
    lv_sec_i    = lv_timestamp MOD lc_day_in_sec.
    ev_time     = lv_sec_i.
* Rest sec and milli seconds
    lv_timsmsec  = lv_timestamp MOD lc_day_in_sec.
    lv_timsmsec  = lv_timsmsec - lv_sec_i.
    ev_msec      = lv_timsmsec * 1000.

*    转换为用户时区时间
    DATA:lv_tstp TYPE timestamp,
         lv_zone TYPE sy-zonlo VALUE 'UTC'.
    CONVERT DATE ev_date TIME ev_time INTO TIME STAMP lv_tstp TIME ZONE lv_zone .
    CONVERT TIME STAMP lv_tstp TIME ZONE sy-zonlo
            INTO DATE ev_date TIME ev_time.
  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>DESERIALIZE_ID
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON                           TYPE        STRING
* | [<-->] PARAMTAB                       TYPE        ABAP_FUNC_PARMBIND_TAB
* | [!CX!] ZCX_JSON
* +--------------------------------------------------------------------------------------
  METHOD deserialize_id.
*/***********************************************************/*
*/ New method using the built-in transformation              /*
*/ included in releases 7.02 and 7.03/7.31 (Kernelpatch 116) /*
*/***********************************************************/*

    TYPE-POOLS: abap.

** Remember function parameter types
**constants:
**  abap_func_exporting type abap_func_parmbind-kind value 10,
**  abap_func_importing type abap_func_parmbind-kind value 20,
**  abap_func_tables    type abap_func_parmbind-kind value 30,
**  abap_func_changing  type abap_func_parmbind-kind value 40.

    DATA:
      rtab       TYPE abap_trans_resbind_tab,
      rlin       TYPE abap_trans_resbind,
      oexcp      TYPE REF TO cx_root,
      etext      TYPE string,
      json_xtext TYPE xstring.

    FIELD-SYMBOLS  TYPE abap_func_parmbind.

    IF json IS INITIAL. EXIT. ENDIF.  " exit method if there is nothing to parse

    " build rtab table for transformation id

    LOOP AT paramtab ASSIGNING .
      IF -kind EQ abap_func_importing. "" va al revés, cuidado!!!
        CONTINUE.
      ENDIF.
      rlin-name  = -name.
      rlin-value = -value.
      APPEND rlin TO rtab.
    ENDLOOP.

    " Convert input JSON variable names to uppercase
    DATA: reader       TYPE REF TO if_sxml_reader,
          writer       TYPE REF TO if_sxml_writer,
          writer_str   TYPE REF TO cl_sxml_string_writer,
          node         TYPE REF TO if_sxml_node,
          open_element TYPE REF TO if_sxml_open_element,
          attributes   TYPE if_sxml_attribute=>attributes.
    FIELD-SYMBOLS   TYPE LINE OF if_sxml_attribute=>attributes.
    json_xtext = cl_abap_codepage=>convert_to( json ).
    reader = cl_sxml_string_reader=>create( json_xtext ).
    writer ?= cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
    DO.
      node = reader->read_next_node( ).
      IF node IS INITIAL.
        EXIT.
      ENDIF.
      IF node->type = if_sxml_node=>co_nt_element_open.
        open_element ?= node.
        attributes  = open_element->get_attributes( ).
        LOOP AT attributes ASSIGNING .
          IF ->qname-name = 'name'.
            ->set_value(
              to_upper( ->get_value( ) ) ).
          ENDIF.
        ENDLOOP.
      ENDIF.
      writer->write_node( node ).
    ENDDO.
    writer_str ?= writer.
    json_xtext = writer_str->get_output( ) .

    TRY.

        CALL TRANSFORMATION id SOURCE XML json_xtext
                               RESULT (rtab).

      CATCH cx_root INTO oexcp.

        etext = oexcp->if_message~get_text( ).
        RAISE EXCEPTION TYPE zcx_json
          EXPORTING
            message = etext.

    ENDTRY.

  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>JSON2ABAP
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON_STRING                    TYPE        STRING(optional)
* | [--->] VAR_NAME                       TYPE        STRING(optional)
* | [--->] PROPERTY_PATH                  TYPE        STRING (default ='json_obj')
* | [<---] PROPERTY_TABLE                 TYPE        JS_PROPERTY_TAB
* | [<-->] JS_OBJECT                      TYPE REF TO CL_JAVA_SCRIPT
* | [<-->] ABAP_DATA                      TYPE        ANY(optional)
* | [!CX!] ZCX_JSON
* +--------------------------------------------------------------------------------------
  METHOD json2abap.
*/************************************************/*
*/ Input any abap data and this method tries to   /*
*/ fill it with the data in the JSON string.      /*
*/  Thanks to Juan Diaz for helping here!!        /*
*/************************************************/*

    TYPE-POOLS: abap, js.

    DATA:
      js_script         TYPE string,
      js_started        TYPE i VALUE 0,
      l_json_string     TYPE string,
      js_property_table TYPE   js_property_tab,
      js_property       TYPE LINE OF js_property_tab,
      l_property_path   TYPE string,
      compname          TYPE string,
      item_path         TYPE string.

    DATA:
      l_type   TYPE c,
      l_value  TYPE string,
      linetype TYPE string,
      l_comp   TYPE LINE OF abap_compdescr_tab.

    DATA:
      datadesc TYPE REF TO cl_abap_typedescr,
      drefdesc TYPE REF TO cl_abap_typedescr,
      linedesc TYPE REF TO cl_abap_typedescr,
      strudesc TYPE REF TO cl_abap_structdescr,
      tabldesc TYPE REF TO cl_abap_tabledescr.

    DATA newline TYPE REF TO data.

    FIELD-SYMBOLS:
       TYPE any,
            TYPE ANY TABLE,
            TYPE any,
          TYPE LINE OF js_property_tab,
        TYPE abap_compdescr.


    DEFINE assign_scalar_value.
      "   &1   
      "   &2   js_property-value
      DESCRIBE FIELD &1 TYPE l_type.
      l_value = &2.
* convert or adapt scalar values to ABAP.
      CASE l_type.
        WHEN 'D'. " date type
          IF l_value CS '-'.
            REPLACE ALL OCCURRENCES OF '-' IN l_value WITH space.
            CONDENSE l_value NO-GAPS.
          ENDIF.
        WHEN 'T'. " time type
          IF l_value CS ':'.
            REPLACE ALL OCCURRENCES OF ':' IN l_value WITH space.
            CONDENSE l_value NO-GAPS.
          ENDIF.
        WHEN OTHERS.
          " may be other conversions or checks could be implemented here.
      ENDCASE.
      &1 = l_value.
    end-of-definition.


    IF js_object IS NOT BOUND.

      IF json_string IS INITIAL. EXIT. ENDIF. " exit method if there is nothing to parse

      l_json_string = json_string.
      " js_object = cl_java_script=>create( STACKSIZE = 16384 ).
      js_object = cl_java_script=>create( stacksize = 16384 heapsize = 960000 ).

***************************************************
*  Parse JSON using JavaScript                    *
***************************************************
      js_object->bind( EXPORTING name_obj = 'abap_data' name_prop = 'json_string'    CHANGING data = l_json_string ).
      js_object->bind( EXPORTING name_obj = 'abap_data' name_prop = 'script_started' CHANGING data = js_started ).

* We use the JavaScript engine included in ABAP to read the JSON string.
* We simply use the recommended way to eval a JSON string as specified
* in RFC 4627 (http://www.ietf.org/rfc/rfc4627.txt).
*
* Security considerations:
*
*   Generally there are security issues with scripting languages.  JSON
*   is a subset of JavaScript, but it is a safe subset that excludes
*   assignment and invocation.
*
*   A JSON text can be safely passed into JavaScript's eval() function
*   (which compiles and executes a string) if all the characters not
*   enclosed in strings are in the set of characters that form JSON
*   tokens.  This can be quickly determined in JavaScript with two
*   regular expressions and calls to the test and replace methods.
*
*      var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
*             text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
*         eval('(' + text + ')');

      CONCATENATE

           'var json_obj; '
           'var json_text; '

           'function start() { '
           '  if(abap_data.script_started) { return; } '
           '  json_text = abap_data.json_string;'
           '  json_obj = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test( '
           '      json_text.replace(/"(\\.|[^"\\])*"/g, ''''))) && '
           '    eval(''('' + json_text + '')''); '
           '  abap_data.script_started = 1; '
           '} '

           'if(!abap_data.script_started) start(); '


         INTO js_script RESPECTING BLANKS SEPARATED BY xnl.

      js_object->compile( script_name = 'json_parser'     script = js_script ).
      js_object->execute( script_name = 'json_parser' ).

      IF js_object->last_error_message IS NOT INITIAL.
        RAISE EXCEPTION TYPE zcx_json
          EXPORTING
            message = js_object->last_error_message.
      ENDIF.

    ENDIF.
** End of JS processing.

**
    IF var_name IS NOT INITIAL.
      CONCATENATE property_path var_name INTO l_property_path SEPARATED BY '.'.
    ELSE.
      l_property_path = property_path.
    ENDIF.
**
**
    js_property_table = js_object->get_properties_scope_global( property_path = l_property_path ).
    property_table = js_property_table.

* Exit if abap_data is not supplied, normally when called
* from json_deserialize to get top level properties
    IF abap_data IS NOT SUPPLIED.
      EXIT.
    ENDIF. "***

*
* Get ABAP data type, dereference if necessary and start
    datadesc = cl_abap_typedescr=>describe_by_data( abap_data ).
    IF datadesc->kind EQ cl_abap_typedescr=>kind_ref.
      ASSIGN abap_data->* TO .
    ELSE.
      ASSIGN abap_data TO .
    ENDIF.
    datadesc = cl_abap_typedescr=>describe_by_data(  ).


    CASE datadesc->kind.

      WHEN cl_abap_typedescr=>kind_elem.
* Scalar: process ABAP elements. Assume no type conversions for the moment.
        IF var_name IS INITIAL.
          RAISE EXCEPTION TYPE zcx_json
            EXPORTING
              message = 'VAR_NAME is required for scalar values.'.
        ENDIF.
        js_property_table = js_object->get_properties_scope_global( property_path = property_path ).
        READ TABLE js_property_table WITH KEY name = var_name INTO js_property.
        IF sy-subrc EQ 0.
          assign_scalar_value  js_property-value.
        ENDIF.


      WHEN cl_abap_typedescr=>kind_struct.
* Process ABAP structures
        strudesc ?= datadesc.
        LOOP AT js_property_table ASSIGNING .
          compname = -name.
          TRANSLATE compname TO UPPER CASE.
          READ TABLE strudesc->components WITH KEY name = compname INTO l_comp.
          IF sy-subrc EQ 0.
            ASSIGN COMPONENT l_comp-name OF STRUCTURE  TO .
            CASE l_comp-type_kind.
              WHEN    cl_abap_typedescr=>typekind_struct1  " 'v'
                   OR cl_abap_typedescr=>typekind_struct2  " 'u'
                   OR cl_abap_typedescr=>typekind_table.   " 'h' (may need a different treatment one day)
                CONCATENATE l_property_path -name INTO item_path SEPARATED BY '.'.
*> Recursive call here
                json2abap( EXPORTING property_path = item_path CHANGING abap_data =  js_object = js_object ).

              WHEN OTHERS.
* Process scalars in structures (same as the kind_elem above)
                assign_scalar_value  -value.

            ENDCASE.
          ENDIF.
        ENDLOOP.

      WHEN cl_abap_typedescr=>kind_table.
* Process ABAP tables
        IF js_property_table IS NOT INITIAL.
          tabldesc ?= datadesc.
          linedesc = tabldesc->get_table_line_type( ).
          linetype = linedesc->get_relative_name( ).
          ASSIGN  TO .
          LOOP AT js_property_table INTO js_property WHERE name NE 'length'. " the JS object length
            CREATE DATA newline TYPE (linetype).
            ASSIGN newline->* TO .
            CASE js_property-kind.
              WHEN 'O'.
                CONCATENATE l_property_path js_property-name INTO item_path SEPARATED BY '.'.
                CONDENSE item_path.
*> Recursive call here
                json2abap( EXPORTING property_path = item_path CHANGING abap_data = newline js_object = js_object ).
              WHEN OTHERS. " Assume scalars, 'S', 'I', or other JS types
                " Process scalars in plain table components(same as the kind_elem above)
                assign_scalar_value  js_property-value.
            ENDCASE.
            INSERT  INTO TABLE .
            FREE newline.
          ENDLOOP.
        ENDIF.

      WHEN OTHERS. " kind_class, kind_intf
        " forget it.

    ENDCASE.


  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON_HANDLER=>JSON_DESERIALIZE
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON                           TYPE        STRING
* | [<-->] PARAMTAB                       TYPE        ABAP_FUNC_PARMBIND_TAB
* | [EXC!] ZCX_JSON
* +--------------------------------------------------------------------------------------
  METHOD json_deserialize.

    TYPE-POOLS: abap, js.

** Remember function parameter types
**constants:
**  abap_func_exporting type abap_func_parmbind-kind value 10,
**  abap_func_importing type abap_func_parmbind-kind value 20,
**  abap_func_tables    type abap_func_parmbind-kind value 30,
**  abap_func_changing  type abap_func_parmbind-kind value 40.

    DATA paramname   TYPE string.
    DATA js_obj      TYPE REF TO cl_java_script.
    DATA js_prop_tab TYPE js_property_tab.

    FIELD-SYMBOLS  TYPE LINE OF js_property_tab.
    FIELD-SYMBOLS     TYPE abap_func_parmbind.

    IF json IS INITIAL. EXIT. ENDIF.

    json2abap( EXPORTING json_string = json  IMPORTING property_table = js_prop_tab  CHANGING js_object = js_obj ).

    LOOP AT js_prop_tab ASSIGNING .
      paramname = -name.
      TRANSLATE paramname TO UPPER CASE.
      READ TABLE paramtab WITH KEY name = paramname ASSIGNING .
      IF sy-subrc EQ 0.
        IF -kind NE abap_func_importing. "" va al revés, cuidado!!!
          json2abap( EXPORTING var_name = -name  CHANGING abap_data = -value js_object = js_obj ).
        ENDIF.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_JSON_HANDLER->NOTES
* +-------------------------------------------------------------------------------------------------+
* | [<-()] TEXT                           TYPE        STRING
* +--------------------------------------------------------------------------------------
  METHOD notes.

    DATA location TYPE string.

    CONCATENATE me->my_url me->my_service '/RFC_SYSTEM_INFO' INTO location.

    CONCATENATE

    'JSON (NEW) handler notes'

    '

About this service...

' 'This is the ABAP implementation of a conversion program that' ' tranforms ABAP data into a JSON representation.' '

' 'It provides a user interface in the form of a ICF service that ' 'allows web invocation of ABAP function modules. It doesn''t matter if they are RFC enabled or not.' '

In this system this service has ' 'been assigned to ICF service ' me->my_service '.' '

' 'In order to invoke a function module, just put its name in the PATH_INFO ' 'of the service URL, as is shown in the following examples.' '

Try the following link to do the default call in JSON format:

'
    location
    '?format=json
' '

A simple syntax allows to get the output in different formats.

' 'The following gets the output in YAML format:' '

'
    location
    '?format=yaml
' '' '

And this will get the output in a basic XML representation:

'
    location
    '?format=xml
' '

And, just for fun, getting it into Perl format could be handy:

'
    location
    '?format=perl
' '

Finnally, you can add a callback to get the JSON response enclosed in a javascript function call,' ' in order to allow a JSONP style response: ' '

'
    location '?format=json&callback=callMe
' '

WARNING

This is work in progress and may not be suitable for use in productive ' 'systems. The interface is somewhat unstable. Please feel free to test it and report ' 'any bug and improvement you may find.' '

Use it at your own risk!' '

For more information: ' 'https://cw.sdn.sap.com/cw/groups/json-adapter-for-abap-function-modules' '

' 'If you have any questions, please contact me at ' '[email protected]' '

' '


' INTO text RESPECTING BLANKS. ENDMETHOD. * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON_HANDLER=>SERIALIZE_ID * +-------------------------------------------------------------------------------------------------+ * | [--->] PARAMTAB TYPE ABAP_FUNC_PARMBIND_TAB * | [--->] PARAMS TYPE ANY(optional) * | [--->] EXCEPTAB TYPE ABAP_FUNC_EXCPBIND_TAB(optional) * | [--->] SHOW_IMPP TYPE ABAP_BOOL(optional) * | [--->] JSONP TYPE STRING(optional) * | [--->] LOWERCASE TYPE ABAP_BOOL (default =ABAP_FALSE) * | [--->] FORMAT TYPE STRING (default ='JSON') * | [--->] FUNCNAME TYPE RS38L_FNAM(optional) * | [--->] CAMELCASE TYPE ABAP_BOOL (default =ABAP_FALSE) * | [<---] O_STRING TYPE STRING * | [!CX!] ZCX_JSON * +-------------------------------------------------------------------------------------- METHOD serialize_id. */***********************************************************/* */ New method using the built-in transformation /* */ included in releases 7.02 and 7.03/7.31 (Kernelpatch 116) /* */ Generates both JSON and XML formats!! */***********************************************************/* */ ** Remember function parameter types **constants: ** abap_func_exporting type abap_func_parmbind-kind value 10, ** abap_func_importing type abap_func_parmbind-kind value 20, ** abap_func_tables type abap_func_parmbind-kind value 30, ** abap_func_changing type abap_func_parmbind-kind value 40. TYPE-POOLS: abap. DATA: stab TYPE abap_trans_srcbind_tab, slin TYPE abap_trans_srcbind, oexcp TYPE REF TO cx_root, etext TYPE string, adata TYPE REF TO data, json_writer TYPE REF TO cl_sxml_string_writer. FIELD-SYMBOLS TYPE abap_func_parmbind. * field-symbols type abap_func_excpbind. LOOP AT paramtab ASSIGNING . IF show_impp NE 'X' AND -kind EQ abap_func_exporting. "" va al revés, cuidado!!! CONTINUE. ENDIF. slin-name = -name. slin-value = -value. APPEND slin TO stab. CLEAR slin. ENDLOOP. IF exceptab IS NOT INITIAL. slin-name = 'EXCEPTION'. GET REFERENCE OF exceptab INTO adata. slin-value = adata. APPEND slin TO stab. CLEAR slin. ENDIF. json_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). TRY. CASE format. WHEN 'XML'. CALL TRANSFORMATION id OPTIONS data_refs = 'embedded' initial_components = 'include' SOURCE (stab) RESULT XML o_string. WHEN OTHERS. CALL TRANSFORMATION id OPTIONS data_refs = 'embedded' initial_components = 'include' SOURCE (stab) RESULT XML json_writer. o_string = cl_abap_codepage=>convert_from( json_writer->get_output( ) ). * json_string = json_writer->get_output( ). IF jsonp IS NOT INITIAL. CONCATENATE jsonp '(' o_string ');' INTO o_string. ENDIF. ENDCASE. CATCH cx_root INTO oexcp. etext = oexcp->if_message~get_text( ). RAISE EXCEPTION TYPE zcx_json EXPORTING message = etext. ENDTRY. ENDMETHOD. * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON_HANDLER=>SERIALIZE_JSON * +-------------------------------------------------------------------------------------------------+ * | [--->] PARAMTAB TYPE ABAP_FUNC_PARMBIND_TAB * | [--->] PARAMS TYPE ANY(optional) * | [--->] EXCEPTAB TYPE ABAP_FUNC_EXCPBIND_TAB(optional) * | [--->] SHOW_IMPP TYPE ABAP_BOOL(optional) * | [--->] JSONP TYPE STRING(optional) * | [--->] LOWERCASE TYPE ABAP_BOOL (default =ABAP_FALSE) * | [--->] CAMELCASE TYPE ABAP_BOOL (default =ABAP_FALSE) * | [<---] O_STRING TYPE STRING * +-------------------------------------------------------------------------------------- METHOD serialize_json. * ABAP based JSON serializer for function modules (January 2013). TYPE-POOLS: abap. ** Remember function parameter types **constants: ** abap_func_exporting type abap_func_parmbind-kind value 10, ** abap_func_importing type abap_func_parmbind-kind value 20, ** abap_func_tables type abap_func_parmbind-kind value 30, ** abap_func_changing type abap_func_parmbind-kind value 40. DATA json_fragments TYPE TABLE OF string. DATA rec_json_string TYPE string. DATA paramname TYPE string. DATA l_lines TYPE i. DATA l_index TYPE i. DATA upcase TYPE xfeld VALUE 'X'. FIELD-SYMBOLS TYPE abap_func_parmbind. FIELD-SYMBOLS TYPE abap_func_excpbind. IF jsonp IS NOT INITIAL. APPEND jsonp TO json_fragments. APPEND '(' TO json_fragments. ENDIF. rec_json_string = '{'. APPEND rec_json_string TO json_fragments. CLEAR rec_json_string. CLEAR l_index. l_lines = lines( paramtab ). LOOP AT paramtab ASSIGNING . IF show_impp NE 'X' AND -kind EQ abap_func_exporting. "" va al revés, cuidado!!! SUBTRACT 1 FROM l_lines. CONTINUE. ENDIF. ADD 1 TO l_index. paramname = -name. IF lowercase EQ abap_true. TRANSLATE paramname TO LOWER CASE. " paramname = to_lower( paramname ). upcase = space. ENDIF. IF camelcase EQ abap_true. paramname = to_mixed( val = paramname case = 'a'). ENDIF. rec_json_string = abap2json( abap_data = -value name = paramname upcase = upcase camelcase = camelcase ). APPEND rec_json_string TO json_fragments. CLEAR rec_json_string. IF l_index < l_lines. APPEND ',' TO json_fragments . ENDIF . ENDLOOP. IF exceptab IS NOT INITIAL. IF l_lines GT 0. APPEND ',' TO json_fragments. ENDIF. rec_json_string = abap2json( abap_data = exceptab upcase = 'X' name = 'EXCEPTION'). APPEND rec_json_string TO json_fragments. CLEAR rec_json_string. ENDIF. rec_json_string = '}'. APPEND rec_json_string TO json_fragments. CLEAR rec_json_string. IF jsonp IS NOT INITIAL. APPEND ');' TO json_fragments. ENDIF. CONCATENATE LINES OF json_fragments INTO o_string. ENDMETHOD. * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON_HANDLER=>SERIALIZE_PERL * +-------------------------------------------------------------------------------------------------+ * | [--->] PARAMTAB TYPE ABAP_FUNC_PARMBIND_TAB * | [--->] PARAMS TYPE ANY(optional) * | [--->] EXCEPTAB TYPE ABAP_FUNC_EXCPBIND_TAB(optional) * | [--->] SHOW_IMPP TYPE ABAP_BOOL(optional) * | [--->] JSONP TYPE STRING(optional) * | [--->] LOWERCASE TYPE ABAP_BOOL (default =ABAP_FALSE) * | [--->] FUNCNAME TYPE RS38L_FNAM * | [<---] PERL_STRING TYPE STRING * +-------------------------------------------------------------------------------------- METHOD serialize_perl. * Just for fun, generate data in Perl Data::Dumper format. TYPE-POOLS: abap. **Remember function parameter types **constants: ** abap_func_exporting type abap_func_parmbind-kind value 10, ** abap_func_importing type abap_func_parmbind-kind value 20, ** abap_func_tables type abap_func_parmbind-kind value 30, ** abap_func_changing type abap_func_parmbind-kind value 40. DATA perl_fragments TYPE TABLE OF string. DATA rec_perl_string TYPE string. DATA paramname TYPE string. DATA l_lines TYPE i. DATA l_index TYPE i. DATA upcase TYPE xfeld VALUE 'X'. DATA perl_var TYPE string. FIELD-SYMBOLS TYPE abap_func_parmbind. FIELD-SYMBOLS TYPE abap_func_excpbind. IF jsonp IS NOT INITIAL. perl_var = jsonp. ELSE. perl_var = funcname. ENDIF. CONCATENATE '$' perl_var ' = {' INTO rec_perl_string. APPEND rec_perl_string TO perl_fragments. CLEAR rec_perl_string. CLEAR l_index. l_lines = lines( paramtab ). LOOP AT paramtab ASSIGNING . IF show_impp NE 'X' AND -kind EQ abap_func_exporting. "" va al revés, cuidado!!! SUBTRACT 1 FROM l_lines. CONTINUE. ENDIF. ADD 1 TO l_index. paramname = -name. IF lowercase EQ abap_true. TRANSLATE paramname TO LOWER CASE. upcase = space. ENDIF. rec_perl_string = abap2perl( abap_data = -value name = paramname upcase = upcase ). APPEND rec_perl_string TO perl_fragments. CLEAR rec_perl_string. IF l_index < l_lines. APPEND ',' TO perl_fragments . ENDIF . ENDLOOP. IF exceptab IS NOT INITIAL. IF l_lines GT 0. APPEND ',' TO perl_fragments. ENDIF. rec_perl_string = abap2perl( abap_data = exceptab upcase = 'X' name = 'EXCEPTION'). APPEND rec_perl_string TO perl_fragments. CLEAR rec_perl_string. ENDIF. rec_perl_string = '};'. APPEND rec_perl_string TO perl_fragments. CLEAR rec_perl_string. CONCATENATE LINES OF perl_fragments INTO perl_string. ENDMETHOD. * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON_HANDLER=>SERIALIZE_XML * +-------------------------------------------------------------------------------------------------+ * | [--->] PARAMTAB TYPE ABAP_FUNC_PARMBIND_TAB * | [--->] PARAMS TYPE ANY(optional) * | [--->] EXCEPTAB TYPE ABAP_FUNC_EXCPBIND_TAB(optional) * | [--->] SHOW_IMPP TYPE ABAP_BOOL(optional) * | [--->] JSONP TYPE STRING(optional) * | [--->] FUNCNAME TYPE RS38L_FNAM * | [--->] LOWERCASE TYPE ABAP_BOOL (default =ABAP_FALSE) * | [--->] FORMAT TYPE STRING * | [<---] O_STRING TYPE STRING * +-------------------------------------------------------------------------------------- METHOD serialize_xml. * Serialize function data into simple XML */ Look at method serialize_id for a new way of doing XML. TYPE-POOLS: abap. ** Remember function parameter types ***constants: *** abap_func_exporting type abap_func_parmbind-kind value 10, *** abap_func_importing type abap_func_parmbind-kind value 20, *** abap_func_tables type abap_func_parmbind-kind value 30, *** abap_func_changing type abap_func_parmbind-kind value 40. DATA rec_xml_string TYPE string. DATA xml_fragments TYPE TABLE OF string. DATA l_funcname TYPE string. DATA paramname TYPE string. FIELD-SYMBOLS TYPE abap_func_parmbind. FIELD-SYMBOLS TYPE abap_func_excpbind. DATA upcase TYPE xfeld VALUE 'X'. CONSTANTS: xml_head TYPE string VALUE ''. APPEND xml_head TO xml_fragments. l_funcname = funcname. IF lowercase EQ abap_true. TRANSLATE l_funcname TO LOWER CASE. upcase = space. ENDIF. CONCATENATE '<' l_funcname '>' INTO rec_xml_string. APPEND rec_xml_string TO xml_fragments. LOOP AT paramtab ASSIGNING . IF show_impp NE 'X' AND -kind EQ abap_func_exporting. "" va al revés, cuidado!!! CONTINUE. ENDIF. paramname = -name. IF lowercase EQ abap_true. TRANSLATE paramname TO LOWER CASE. ENDIF. rec_xml_string = abap2xml( name = paramname abap_data = -value upcase = upcase ). APPEND rec_xml_string TO xml_fragments. ENDLOOP. IF exceptab IS NOT INITIAL. rec_xml_string = abap2xml( name = 'EXCEPTION' abap_data = exceptab upcase = upcase ). APPEND rec_xml_string TO xml_fragments. ENDIF. CONCATENATE '' INTO rec_xml_string. APPEND rec_xml_string TO xml_fragments. CONCATENATE LINES OF xml_fragments INTO o_string. ENDMETHOD. * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON_HANDLER=>SERIALIZE_YAML * +-------------------------------------------------------------------------------------------------+ * | [--->] PARAMTAB TYPE ABAP_FUNC_PARMBIND_TAB * | [--->] PARAMS TYPE ANY * | [--->] EXCEPTAB TYPE ABAP_FUNC_EXCPBIND_TAB * | [--->] SHOW_IMPP TYPE ABAP_BOOL * | [--->] JSONP TYPE STRING * | [--->] LOWERCASE TYPE ABAP_BOOL (default =ABAP_FALSE) * | [<---] YAML_STRING TYPE STRING * +-------------------------------------------------------------------------------------- METHOD serialize_yaml. * Now, go and represent function data in YAML (http://yaml.org) TYPE-POOLS: abap. ** Remember function parameter types **constants: ** abap_func_exporting type abap_func_parmbind-kind value 10, ** abap_func_importing type abap_func_parmbind-kind value 20, ** abap_func_tables type abap_func_parmbind-kind value 30, ** abap_func_changing type abap_func_parmbind-kind value 40. DATA yaml_fragments TYPE TABLE OF string. DATA rec_yaml_string TYPE string. DATA rec_yaml_table TYPE TABLE OF string. DATA paramname TYPE string. FIELD-SYMBOLS TYPE abap_func_parmbind. FIELD-SYMBOLS TYPE abap_func_excpbind. DATA upcase TYPE xfeld VALUE 'X'. DATA yaml_head TYPE string VALUE '--- #YAML:1.0'. CONCATENATE yaml_head xnl INTO rec_yaml_string. APPEND rec_yaml_string TO yaml_fragments. CLEAR rec_yaml_string. LOOP AT paramtab ASSIGNING . IF show_impp NE 'X' AND -kind EQ abap_func_exporting. "" va al revés, cuidado!!! CONTINUE. ENDIF. paramname = -name. IF lowercase EQ abap_true. TRANSLATE paramname TO LOWER CASE. upcase = space. ENDIF. rec_yaml_string = abap2yaml( abap_data = -value name = paramname upcase = upcase ). APPEND rec_yaml_string TO yaml_fragments. CLEAR rec_yaml_string. ENDLOOP. IF exceptab IS NOT INITIAL. rec_yaml_string = abap2yaml( abap_data = exceptab name = 'EXCEPTION' upcase = 'X' ). APPEND rec_yaml_string TO yaml_fragments. CLEAR rec_yaml_string. ENDIF. * append xnl to yaml_fragments. CONCATENATE LINES OF yaml_fragments INTO yaml_string. * if jsonp is not initial. * concatenate jsonp '(' yaml_string ');' into yaml_string. * endif. ENDMETHOD. ENDCLASS.

工具类

zcl_log_handler 保存日志
CLASS zcl_log_handler DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    TYPE-POOLS abap .

    METHODS constructor
      IMPORTING
        !function_name TYPE rs38l_fnam .
    METHODS add_paramater
      IMPORTING
        !name  TYPE abap_parmname
        !value TYPE any
      RAISING
        cx_ai_system_fault .
    METHODS save_log
      IMPORTING
        !is_input TYPE zif_msg .
  PROTECTED SECTION.
  PRIVATE SECTION.

    DATA paramtab TYPE abap_func_parmbind_tab .
    DATA exceptab TYPE abap_func_excpbind_tab .
    DATA:
      t_params_p TYPE TABLE OF rfc_fint_p .
ENDCLASS.



CLASS zcl_log_handler IMPLEMENTATION.


* ---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_LOG_HANDLER->ADD_PARAMATER
* +-------------------------------------------------------------------------------------------------+
* | [--->] NAME                           TYPE        ABAP_PARMNAME
* | [--->] VALUE                          TYPE        ANY
* | [!CX!] CX_AI_SYSTEM_FAULT
* +--------------------------------------------------------------------------------------
  METHOD add_paramater.
    FIELD-SYMBOLS  TYPE abap_func_parmbind.
    READ TABLE paramtab ASSIGNING  WITH KEY name = name.
    IF sy-subrc = 0.
      GET REFERENCE OF value INTO -value.
    ELSE.

      RAISE EXCEPTION TYPE cx_ai_system_fault
        EXPORTING
          code      = 'E'
          errortext = '输入参数不存在'.

    ENDIF.
  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_LOG_HANDLER->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] FUNCTION_NAME                  TYPE        RS38L_FNAM
* +--------------------------------------------------------------------------------------
  METHOD constructor.

    REFRESH:paramtab,exceptab,t_params_p.
    CALL METHOD zcl_json_handler=>build_params
      EXPORTING
        function_name          = function_name
      IMPORTING
        paramtab               = paramtab
        exceptab               = exceptab
        params                 = t_params_p
      EXCEPTIONS
        invalid_function       = 1
        unsupported_param_type = 2
        OTHERS                 = 3.
    IF sy-subrc = 1.

      RAISE EXCEPTION TYPE cx_ai_system_fault
        EXPORTING
          code      = 'E'
          errortext = '函数名错误'.
    ELSEIF sy-subrc <> 0.
      RAISE EXCEPTION TYPE cx_ai_system_fault
        EXPORTING
          code      = 'E'
          errortext = '函数名错误'.
    ENDIF.

  ENDMETHOD.


* ---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_LOG_HANDLER->SAVE_LOG
* +-------------------------------------------------------------------------------------------------+
* | [--->] IS_INPUT                       TYPE        ZIF_MSG
* +--------------------------------------------------------------------------------------
  METHOD save_log.

    DATA:ls_zif_msg TYPE zif_msg.

    ls_zif_msg = is_input.

    CALL METHOD zcl_json_handler=>serialize_json
      EXPORTING
        paramtab  = paramtab
        show_impp = 'X'
      IMPORTING
        o_string  = ls_zif_msg-paylod.

    MODIFY zif_msg FROM ls_zif_msg.

    COMMIT WORK .

  ENDMETHOD.
ENDCLASS.

接口日志展示ALV

report : ZIF_DISPLAY

*& Responsibility
*&---------------------------------------------------------------------*
* Program Name:ZIF_DISPLAY
* Date written:
* Author's name:
* Last update:
* Program title:接口日志查询
* Project Name:
* Version:
*&---------------------------------------------------------------------*
* Description: (Incl. Related Function Area and System)
*&---------------------------------------------------------------------*
*
*&---------------------------------------------------------------------*
* Change History
*&---------------------------------------------------------------------*
*     Date   |   Programmer   |   Corr. #   |   Description
*            |                |             |
*            |                |             |
*&---------------------------------------------------------------------*
REPORT zif_display.

DATA: gt_itab TYPE STANDARD TABLE OF zif_msg.

*---------------------------------------------------------------------*
* 选择屏幕
*---------------------------------------------------------------------*
TABLES:usr02.
SELECTION-SCREEN:BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
  SELECT-OPTIONS:
      s_erdat FOR sy-datum,
      s_ernam FOR usr02-bname.
SELECTION-SCREEN END OF BLOCK b1.

*&---------------------------------------------------------------------*
*&      START-OF-SELECTION
*&---------------------------------------------------------------------*
START-OF-SELECTION.

  PERFORM get_data.

  PERFORM display.


FORM get_data .

  SELECT *
  FROM zif_msg
  INTO TABLE gt_itab
  WHERE erdat IN s_erdat
  AND   ernam IN s_ernam.

  SORT gt_itab BY erdat DESCENDING uzeit DESCENDING.

ENDFORM.                    "GET_DATA

*&---------------------------------------------------------------------*
*& Form display
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM display .

  DATA:ls_layout     TYPE lvc_s_layo.

  ls_layout-zebra = 'X'.
  ls_layout-cwidth_opt = 'X'.
  ls_layout-sel_mode = 'B'.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
    EXPORTING
      i_callback_program      = sy-repid
      i_callback_user_command = 'FRM_USER_COMMAND'
      is_layout_lvc           = ls_layout
      i_structure_name        = 'ZIF_MSG'
*     it_fieldcat_lvc         = gt_fieldcat
      i_save                  = 'A'
    TABLES
      t_outtab                = gt_itab
    EXCEPTIONS
      program_error           = 1
      OTHERS                  = 2.

  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
             WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

ENDFORM.

FORM frm_user_command USING iv_ucomm       TYPE sy-ucomm
                            is_selfield     TYPE slis_selfield.

  DATA: l_grid  TYPE REF TO cl_gui_alv_grid.


  CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
    IMPORTING
      e_grid = l_grid.

  CALL METHOD l_grid->check_changed_data.

  CASE iv_ucomm.

    WHEN '&IC1'.
      READ TABLE gt_itab INDEX  is_selfield-tabindex INTO DATA(ls_itab).  "获取单击行
      IF sy-subrc IS INITIAL.

        PERFORM display_json  USING ls_itab.
      ENDIF.

*  WHEN '&RESEND'.重新发送

*      DATA:lt_para_tab  TYPE abap_func_parmbind_tab,
*           ls_para_line LIKE LINE OF lt_para_tab,
*           lt_exceptab  TYPE abap_func_excpbind_tab,
*           lt_params_p  TYPE TABLE OF rfc_fint_p,
*           params_p     TYPE rfc_fint_p,
*           oexcp        TYPE REF TO cx_root,
*           lv_etext     TYPE string.
*      FIELD-SYMBOLS  TYPE abap_func_parmbind.
*      CALL METHOD zcl_json_handler=>build_params
*        EXPORTING
*          function_name          = ls_itab-proname
*        IMPORTING
*          paramtab               = lt_para_tab
*          exceptab               = lt_exceptab
*          params                 = lt_params_p
*        EXCEPTIONS
*          invalid_function       = 1
*          unsupported_param_type = 2
*          OTHERS                 = 3.
*      IF sy-subrc <> 0.
*        CONCATENATE '函数名错误. ' sy-msgid sy-msgty sy-msgno ': '
*                sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
*                INTO lv_etext SEPARATED BY '-'.
*        MESSAGE lv_etext TYPE 'E'.
*      ENDIF.
*      TRY.
*          CALL METHOD zcl_json_handler=>json_deserialize
*            EXPORTING
*              json     = ls_itab-paylod
*            CHANGING
*              paramtab = lt_para_tab.
*          TRY.
*              CALL FUNCTION ls_itab-proname
*                PARAMETER-TABLE lt_para_tab
*                EXCEPTION-TABLE lt_exceptab.
*            CATCH cx_root INTO oexcp.
*              lv_etext = oexcp->if_message~get_longtext(  preserve_newlines = abap_true ).
*              MESSAGE lv_etext TYPE 'E'.
*
*          ENDTRY.
*        CATCH cx_root INTO oexcp.
*          lv_etext = oexcp->if_message~get_text( ).
*          MESSAGE lv_etext TYPE 'E'.
*      ENDTRY.


  ENDCASE.
**刷新
  CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
    IMPORTING
      e_grid = l_grid.
  CALL METHOD l_grid->check_changed_data.

  CALL METHOD l_grid->refresh_table_display.

  is_selfield-refresh = 'X' .

ENDFORM.                    "frm_user_command

FORM display_json  USING    is_itab TYPE zif_msg.

  DATA:lv_json TYPE string.

  DATA(out) = cl_demo_output=>new( ).

  DATA :reader     TYPE REF TO if_sxml_reader,
        writer     TYPE REF TO if_sxml_writer,
        writer_str TYPE REF TO cl_sxml_string_writer.
  DATA json TYPE xstring.


  lv_json = is_itab-paylod.
  out->begin_section( |函数:{ is_itab-proname }| ).
  CHECK lv_json <> ''.
  IF lv_json+0(1) = '<'.
    out->write_xml( lv_json ).
  ELSE.
    out->write_json( lv_json ).
  ENDIF.
  IF sy-subrc <> 0.
    MESSAGE '要显示的报文不存在!' TYPE 'S'.
  ELSE.
    out->display(  ).
  ENDIF.
ENDFORM.

函数demo

FUNCTION zdemo_02.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(IV_INPUT) TYPE  CHAR10
*"     REFERENCE(IV_INPUT2) TYPE  CHAR10
*"  EXPORTING
*"     REFERENCE(EV_MSG) TYPE  STRING
*"----------------------------------------------------------------------
*初始化获取函数相关自身信息
  DATA: lt_callstack TYPE abap_callstack.
  CALL FUNCTION 'SYSTEM_CALLSTACK'
    IMPORTING
      callstack = lt_callstack.

  DATA(lv_func_name) = VALUE #( lt_callstack[ 1 ]-blockname OPTIONAL ).

  SELECT funcname, paramtype, pposition, parameter, structure
  FROM fupararef
  WHERE funcname = @lv_func_name
  INTO TABLE @DATA(lt_parameters_tab).

  SORT lt_parameters_tab BY paramtype pposition.
*初始化获取函数相关自身信息

  TRY.
      DATA(lv_uuid) = cl_system_uuid=>create_uuid_c32_static( ).
    CATCH cx_uuid_error.
  ENDTRY.

  ev_msg = 'S'.

*save log
  DATA:ls_zif_msg              TYPE zif_msg.
  DATA:lr_log                  TYPE REF TO zcl_log_handler.
  DATA:lo_sys_exception2       TYPE REF TO cx_ai_system_fault.
  .
  ls_zif_msg-guid        = lv_uuid.
  ls_zif_msg-proname     = 'ZDEMO_02'.
  ls_zif_msg-erdat       = sy-datum.
  ls_zif_msg-ernam       = sy-uname.
  ls_zif_msg-uzeit       = sy-uzeit.
  ls_zif_msg-type        = ''.
  ls_zif_msg-msg         = ''.
*  ls_zif_msg-paylod      = lv_uuid.
  ls_zif_msg-cust_field1 = iv_input.
*  ls_zif_msg-cust_field2 = lv_uuid.
*  ls_zif_msg-cust_field3 = lv_uuid.

  FIELD-SYMBOLS:    TYPE any.
  TRY.
      lr_log = NEW #( CONV #( lv_func_name ) ).
*优化写法
      LOOP AT lt_parameters_tab  ASSIGNING FIELD-SYMBOL().
        ASSIGN (-parameter) TO .
        lr_log->add_paramater( name = -parameter value =  ).
      ENDLOOP.
*原始写法
*      lr_log->add_paramater( name = 'IV_INPUT' value = iv_input ).
*      lr_log->add_paramater( name = 'EV_MSG'   value = ev_msg ).
**原始写法
      lr_log->save_log( is_input = ls_zif_msg ).
    CATCH cx_ai_system_fault INTO lo_sys_exception2.       "
  ENDTRY.

ENDFUNCTION.

你可能感兴趣的:(ABAP,开发语言)