把SAP银企直连接时,我们使用DMEE,把结构数据转换为XML,在接收到数据后,使用STRANS把XML转换为结构化数据,其实STRANS,也可以把结构化数据转换为JSON,
1.法一 、STRANS 转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
*&********************************************************************* *& PROGRAM NAME : ZTEST20 *& Module Name : *& Apply Author : *& Author : *& Started on : 2020-07-01 *& Transaction : ZTEST20 *& Program type : Report *& Program ID : ZTEST20 *& Program Description : 功能描述。。。。。。 *&*&******************************************************************* *& REVISION LOG * *& * *& LOG# DATE AUTHOR DESCRIPTION * *& ---- ---- ------ ----------- * *& 0001 2020-07-01 XXX Initial Creation *&********************************************************************* REPORT ZTEST20. CLASS demo DEFINITION. PUBLIC SECTION. CLASS-METHODS main. PRIVATE SECTION. CLASS-METHODS: display_as_text IMPORTING json TYPE xstring, display_as_html IMPORTING json TYPE xstring. ENDCLASS. CLASS demo IMPLEMENTATION. METHOD main. "Get some data into an internal table TYPES: BEGIN OF carrier, carrid TYPE scarr-carrid, carrname TYPE scarr-carrname, url TYPE scarr-url, END OF carrier. DATA carriers TYPE TABLE OF carrier. SELECT carrid carrname url FROM scarr INTO CORRESPONDING FIELDS OF TABLE carriers. "Create JSON-writer and call simple transformation DATA json_writer TYPE REF TO cl_sxml_string_writer. DATA writer TYPE REF TO if_sxml_writer. json_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). writer ?= json_writer. writer->set_option( option = if_sxml_writer=>co_opt_linebreaks ). writer->set_option( option = if_sxml_writer=>co_opt_indent ). CALL TRANSFORMATION demo_st_json_table SOURCE carriers = carriers RESULT XML json_writer. "Get JSON-String from writer DATA json TYPE xstring. json = json_writer->get_output( ). "Two ways of displaying the JSON string display_as_text( json ). display_as_html( json ). "Back to ABAP, verify that transformation is symmetric DATA result LIKE carriers. CALL TRANSFORMATION demo_st_json_table SOURCE XML json RESULT carriers = result. ASSERT result = carriers. ENDMETHOD. METHOD display_as_text. "Simple output of JSON in text edit control DATA text TYPE string. text = cl_abap_codepage=>convert_from( json ). cl_demo_text=>DISPLAY_STRING( text ). ENDMETHOD. METHOD display_as_html. "Beautified output of JSON in HTML browser DATA html TYPE string. CALL TRANSFORMATION sjson2html SOURCE XML json RESULT XML html. cl_abap_browser=>show_html( html_string = html ). ENDMETHOD. ENDCLASS. START-OF-SELECTION. demo=>main( ). |
上面的程序中使用了事务码 STRANS定义的DEMO_ST_JSON_TABLE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?sap.transform simple?> <tt:transform xmlns:tt="http://www.sap.com/transformation-templates"> <tt:root name="CARRIERS"/> <tt:template> <array> <tt:loop ref=".CARRIERS"> <object> <str name="Carrier-Id"> <tt:value ref="$ref.carrid"/> </str> <str name="Carrier"> <tt:value ref="$ref.carrname"/> </str> <str name="URL"> <tt:value ref="$ref.url"/> </str> </object> </tt:loop> </array> </tt:template> </tt:transform> |
2.法二、/ui2/cl_json
此方法,应该是最好的转换为JSON的方法,此方法可使用用驼峰参数,实现大不驼峰转换功能。并能解决其它转换时的双引号等问题。他不仅支持结构、内表转换成JSON,还支持嵌套结构deep structure这种复杂的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
DATA: lt_flight TYPE STANDARD TABLE OF sflight, lrf_descr TYPE REF TO cl_abap_typedescr, lv_json TYPE string. SELECT * FROM sflight INTO TABLE lt_flight. * serialize table lt_flight into JSON, skipping initial fields and converting ABAP field names into camelCase lv_json = /ui2/cl_json=>serialize( data = lt_flight compress = abap_true pretty_name = /ui2/cl_json=>pretty_mode-camel_case ). WRITE / lv_json. CLEAR lt_flight. * deserialize JSON string json into internal table lt_flight doing camelCase to ABAP like field name mapping /ui2/cl_json=>deserialize( EXPORTING json = lv_json pretty_name = /ui2/cl_json=>pretty_mode-camel_case CHANGING data = lt_flight ). * serialize ABAP object into JSON string lrf_descr = cl_abap_typedescr=>describe_by_data( lt_flight ). lv_json = /ui2/cl_json=>serialize( lrf_descr ). WRITE / lv_json. |
3.法三、CL_TREX_JSON_SERIALIZER与CL_TREX_JSON_DESERIALIZER
对于一些旧的系统不支持/ui2/cl_json,可以使用CL_TREX_JSON_SERIALIZER与CL_TREX_JSON_DESERIALIZER,这两方法来实现转换,
CL_TREX_JSON_SERIALIZER
:将 ABAP 内表转换为 json 格式CL_TREX_JSON_DESERIALIZER
:json 转换为 ABAP 内表
这两个类有一点点问题,序列化生成的格式 key 没有引号,可能导致外部解析的失败。比如
1 2 3 4 5 6 7 8 9 10 |
[ { id: "001", name: "Stone" }, { id: "002", name: "Brown" } ] |
而我们需要的是下面的格式:
1 2 3 4 5 6 7 8 9 10 |
[ { "id": "001", "name": "Stone" }, { "id": "002", "name": "Brown" } ] |
所以需要对两个类进行改造,以符合自己的需求。首先我们使用事务码 SE24 将 CL_TREX_JSON_SERIALIZER
类拷贝一个新类,另存为 ZCL_TREX_JSON_SERIALIZER
,然后将 RECURSE()
方法做两点改变:,43是增加的内容,还有一个问题,JAVA系统一般都会使用驼峰转换规则转换字段名(BUKRS_MATNR要转换为bukrsMatnr),而默认的会把字段转换为小写字母(BUKRS_MATNR要转换为bukrs_matnr),所以在55修改为55-70行为驼峰转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
METHOD RECURSE. DATA: L_TYPE TYPE C , L_COMPS TYPE I , L_LINES TYPE I , L_INDEX TYPE I , L_VALUE TYPE STRING . FIELD-SYMBOLS: <ITAB> TYPE ANY TABLE , <COMP> TYPE ANY . DATA: TOKENS TYPE TABLE OF CHAR128. FIELD-SYMBOLS: <TOKEN> LIKE LINE OF TOKENS. DESCRIBE FIELD DATA TYPE L_TYPE COMPONENTS L_COMPS . IF L_TYPE = CL_ABAP_TYPEDESCR=>TYPEKIND_TABLE . * itab -> array APPEND '[' TO ME->FRAGMENTS . ASSIGN DATA TO <ITAB> . L_LINES = LINES( <ITAB> ) . LOOP AT <ITAB> ASSIGNING <COMP> . ADD 1 TO L_INDEX . RECURSE( <COMP> ) . IF L_INDEX < L_LINES . APPEND C_COMMA TO ME->FRAGMENTS . ENDIF . ENDLOOP . APPEND ']' TO FRAGMENTS . ELSE . IF L_COMPS IS INITIAL . * field -> scalar * todo: format L_VALUE = DATA . REPLACE ALL OCCURRENCES OF '\' IN L_VALUE WITH '\\' . REPLACE ALL OCCURRENCES OF '''' IN L_VALUE WITH '\''' . 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' . CONDENSE L_VALUE. CONCATENATE '"' L_VALUE '"' INTO L_VALUE . APPEND L_VALUE TO ME->FRAGMENTS . ELSE . * structure -> object DATA L_TYPEDESCR TYPE REF TO CL_ABAP_STRUCTDESCR . FIELD-SYMBOLS <ABAPCOMP> TYPE ABAP_COMPDESCR . APPEND '{' TO ME->FRAGMENTS . L_TYPEDESCR ?= CL_ABAP_TYPEDESCR=>DESCRIBE_BY_DATA( DATA ) . LOOP AT L_TYPEDESCR->COMPONENTS ASSIGNING <ABAPCOMP> . L_INDEX = SY-TABIX . * concatenate <abapcomp>-name c_colon into l_value . *--------------------------------------------------------------------* * 驼峰转换 L_VALUE = <ABAPCOMP>-NAME. TRANSLATE L_VALUE TO LOWER CASE. TRANSLATE L_VALUE USING `/_:_~_`. SPLIT L_VALUE AT `_` INTO TABLE TOKENS. LOOP AT TOKENS ASSIGNING <TOKEN> FROM 2. TRANSLATE <TOKEN>(1) TO UPPER CASE. ENDLOOP. CONCATENATE LINES OF TOKENS INTO L_VALUE. REPLACE ALL OCCURRENCES OF `*` IN L_VALUE WITH `_`. CONCATENATE '"' L_VALUE '"' C_COLON INTO L_VALUE. * translate l_value to lower case . *--------------------------------------------------------------------* APPEND L_VALUE TO ME->FRAGMENTS . ASSIGN COMPONENT <ABAPCOMP>-NAME OF STRUCTURE DATA TO <COMP> . RECURSE( <COMP> ) . IF L_INDEX < L_COMPS . APPEND C_COMMA TO ME->FRAGMENTS . ENDIF . ENDLOOP . APPEND '}' TO ME->FRAGMENTS . ENDIF . ENDIF . ENDMETHOD. |
相对应地, 将 CL_TREX_JSON_DESERIALIZER
拷贝成为 ZCL_TREX_JSON_DESERIALIZER
,并且对 deserialize_object
方法做两点变更
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
METHOD deserialize_object. DATA: l_node_type TYPE REF TO cl_abap_typedescr , l_ref TYPE REF TO object . ADD 1 TO offset . "skip { l_node_type = cl_abap_typedescr=>describe_by_data( node ) . * prepare for dynamic access CASE l_node_type->kind . WHEN cl_abap_typedescr=>kind_ref . l_ref = node . WHEN cl_abap_typedescr=>kind_struct . WHEN OTHERS . RAISE EXCEPTION TYPE cx_trex_serialization . ENDCASE . DATA: l_done TYPE abap_bool , l_len TYPE i , l_name TYPE string . * handle each component WHILE l_done = abap_false . "find next key FIND REGEX '"(\w+)\s*":' IN SECTION OFFSET offset OF json MATCH OFFSET offset MATCH LENGTH l_len SUBMATCHES l_name . IF sy-subrc <> 0 . RAISE EXCEPTION TYPE cx_trex_serialization . ENDIF . ADD l_len TO offset . FIELD-SYMBOLS <comp> TYPE ANY . * dynamic binding to component TRANSLATE l_name TO UPPER CASE . CASE l_node_type->kind . WHEN cl_abap_typedescr=>kind_ref . ASSIGN l_ref->(l_name) TO <comp> . WHEN cl_abap_typedescr=>kind_struct . ASSIGN COMPONENT l_name OF STRUCTURE node TO <comp> . IF sy-subrc <> 0. CONTINUE. ENDIF. WHEN OTHERS . RAISE EXCEPTION TYPE cx_trex_serialization . ENDCASE . DATA: l_comp_type TYPE REF TO cl_abap_typedescr , l_ref_type TYPE REF TO cl_abap_refdescr . * check component type l_comp_type = cl_abap_typedescr=>describe_by_data( <comp> ) . CASE l_comp_type->kind . * create instance if it's an oref WHEN cl_abap_typedescr=>kind_ref . l_ref_type ?= l_comp_type . l_comp_type = l_ref_type->get_referenced_type( ) . CREATE OBJECT <comp> TYPE (l_comp_type->absolute_name) . ENDCASE . * deserialize current component deserialize_node( EXPORTING json = json CHANGING offset = offset node = <comp> ) . FIND REGEX ',|\}' IN SECTION OFFSET offset OF json MATCH OFFSET offset . IF sy-subrc <> 0 . RAISE EXCEPTION TYPE cx_trex_serialization . ENDIF . IF json+offset(1) = '}' . l_done = abap_true . ENDIF . ADD 1 TO offset . ENDWHILE . ENDMETHOD. |
调用 ZCL_TREX_JSON_SERIALIZER 实现序列化以及调用 ZCL_TREX_JSON_DESERIALIZER 实现反序列化的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
REPORT zlm_abap_json. DATA: serializer TYPE REF TO zcl_trex_json_serializer, lv_json TYPE string. DATA: BEGIN OF ls_json, id TYPE string, name TYPE string, END OF ls_json. DATA: lt_json LIKE STANDARD TABLE OF ls_json. CLEAR ls_json. ls_json-id = '001'. ls_json-name = 'Stone'. APPEND ls_json TO lt_json. CLEAR ls_json. ls_json-id = '002'. ls_json-name = 'Brown'. APPEND ls_json TO lt_json. CREATE OBJECT serializer EXPORTING data = lt_json[]. CALL METHOD serializer->serialize( ). lv_json = serializer->get_data( ). WRITE / lv_json. * Deserialze WRITE /. WRITE: / 'Deseriaze json string to internal table: '. DATA: deserializer TYPE REF TO zcl_trex_json_deserializer. CLEAR lt_json. CREATE OBJECT deserializer. CALL METHOD deserializer->deserialize( EXPORTING json = lv_json IMPORTING abap = lt_json[] ). LOOP AT lt_json INTO ls_json. WRITE : / ls_json-id, ls_json-name. ENDLOOP. |
4.其它
类CL_STW_PARSE_JSON,也可把字符串转换成结构 化数据
1 2 3 4 5 |
DATA: LV_PARSE_JSON TYPE REF TO CL_STW_PARSE_JSON, *{ "code": 200, "success": true, "data": null, "msg": "操作成功"} CREATE OBJECT LV_PARSE_JSON . LV_PARSE_JSON->JSON_TO_DATA( EXPORTING IV_JSON = LV_RESPON CHANGING C_DATA = LS_RESPON ). |