正如人们可能知道的那样,我们有这样一个方便的 MOVE-CORRESPONDING 子句,如
EXPANDING NESTED TABLES
:
MOVE-CORRESPONDING: <m_source> TO <m_target> EXPANDING NESTED TABLES.
它的基本作用是解析每个层次结构级别上的表和结构类型(如果它们不 1:1 匹配但具有公共字段和行类型)。这正是我当前项目所需要的:我有 7-10 层代理结构层次结构,需要相互复制。
问题是我的系统是ABAP 7.31 SP 10,所以这个条款对我来说不可用。我可以轻松发明一些像这样令人毛骨悚然的 RTTS 结构(示意性地):
LOOP AT <m_source>-components ASSIGNING <fs_components_l0>.
LOOP AT <fs_components_l0>-components ASSIGNING <fs_components_l1>.
....
DO N TIMES.
ASSIGN COMPONENT n OF STRUCTURE <fs_components_l1> to <fs_components_l1_comp>.
MOVE-CORRESPONDING ...
ENDDO.
ENDLOOP.
ENDLOOP.
但这可能会非常冗长,具有多个层次结构,并且不太可维护。
有人发明过更简洁有效的替代品吗
EXPANDING NESTED TABLES
?
如果您使用 RTTS 和递归编程,我不认为它“令人毛骨悚然”(正如您所说)。该代码将非常易于维护。
该类名为
lcl_move_corresponding_nested
,使用方法如下:
lcl_move_corresponding_nested=>process( EXPORTING source = structure1
IMPORTING target = structure2 ).
这是代码:
CLASS lcx_move_corresponding_nested DEFINITION INHERITING FROM cx_static_check.
ENDCLASS.
CLASS lcl_move_corresponding_nested DEFINITION.
PUBLIC SECTION.
CLASS-METHODS process
IMPORTING source TYPE any
EXPORTING target TYPE any
RAISING lcx_move_corresponding_nested.
PRIVATE SECTION.
CLASS-METHODS process_structure
IMPORTING !source TYPE any
EXPORTING !target TYPE any
RAISING lcx_move_corresponding_nested.
CLASS-METHODS process_itab
IMPORTING !source TYPE ANY TABLE
EXPORTING !target TYPE ANY TABLE
RAISING lcx_move_corresponding_nested.
ENDCLASS.
CLASS lcl_move_corresponding_nested IMPLEMENTATION.
METHOD process.
DATA source_rtts TYPE REF TO cl_abap_datadescr.
DATA target_rtts TYPE REF TO cl_abap_datadescr.
source_rtts ?= cl_abap_typedescr=>describe_by_data( source ).
target_rtts ?= cl_abap_typedescr=>describe_by_data( target ).
IF source_rtts->kind <> target_rtts->kind.
RAISE EXCEPTION TYPE lcx_move_corresponding_nested.
ENDIF.
CASE source_rtts->kind.
WHEN cl_abap_typedescr=>kind_table.
process_itab( EXPORTING source = source
IMPORTING target = target ).
WHEN cl_abap_typedescr=>kind_struct.
process_structure( EXPORTING source = source
IMPORTING target = target ).
WHEN OTHERS.
target = source.
ENDCASE.
ENDMETHOD.
METHOD process_structure.
DATA source_rtts_structure TYPE REF TO cl_abap_structdescr.
DATA source_component TYPE REF TO abap_compdescr.
FIELD-SYMBOLS <source_component> TYPE any.
FIELD-SYMBOLS <target_component> TYPE any.
CLEAR target.
source_rtts_structure ?= cl_abap_typedescr=>describe_by_data( source ).
LOOP AT source_rtts_structure->components REFERENCE INTO source_component.
ASSIGN COMPONENT source_component->name OF STRUCTURE source TO <source_component>.
ASSERT sy-subrc = 0.
ASSIGN COMPONENT source_component->name OF STRUCTURE target TO <target_component>.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
process( EXPORTING source = <source_component>
IMPORTING target = <target_component> ).
ENDLOOP.
ENDMETHOD.
METHOD process_itab.
DATA source_rtts_table TYPE REF TO cl_abap_tabledescr.
DATA ref_to_target_itab_line TYPE REF TO data.
DATA source_rtts_table_line TYPE REF TO cl_abap_datadescr.
FIELD-SYMBOLS <source_itab_line> TYPE any.
FIELD-SYMBOLS <target_itab_line> TYPE any.
CLEAR target.
CREATE DATA ref_to_target_itab_line LIKE LINE OF target.
ASSIGN ref_to_target_itab_line->* TO <target_itab_line>.
source_rtts_table ?= cl_abap_typedescr=>describe_by_data( source ).
LOOP AT source ASSIGNING <source_itab_line>.
process( EXPORTING source = <source_itab_line>
IMPORTING target = <target_itab_line> ).
INSERT <target_itab_line> INTO TABLE target.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
测试数据(仅适用于ABAP 7.40):
* Example data taken from DEMO_MOVE_CORRESPONDING_ITAB and enriched.
CLASS ltc_app DEFINITION
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS
FINAL.
PRIVATE SECTION.
METHODS test FOR TESTING RAISING cx_static_check.
METHODS test_2 FOR TESTING RAISING cx_static_check.
METHODS test_3 FOR TESTING RAISING cx_static_check.
TYPES c3 TYPE c LENGTH 4.
TYPES: BEGIN OF eline1,
col1 TYPE c3,
col2 TYPE c3,
END OF eline1.
TYPES: BEGIN OF eline2,
col2 TYPE c3,
col3 TYPE c3,
END OF eline2.
TYPES: BEGIN OF iline1,
col1 TYPE c3,
col2 TYPE STANDARD TABLE OF eline1 WITH EMPTY KEY,
END OF iline1.
TYPES: BEGIN OF iline2,
col2 TYPE STANDARD TABLE OF eline2 WITH EMPTY KEY,
col3 TYPE c3,
END OF iline2.
TYPES: BEGIN OF line1,
col1 TYPE c3,
col2 TYPE c3,
col3 TYPE STANDARD TABLE OF iline1 WITH EMPTY KEY,
END OF line1.
TYPES: BEGIN OF line2,
col2 TYPE c3,
col3 TYPE STANDARD TABLE OF iline2 WITH EMPTY KEY,
col4 TYPE c3,
END OF line2.
TYPES ty_itab1 TYPE STANDARD TABLE OF line1 WITH EMPTY KEY.
TYPES ty_itab2 TYPE STANDARD TABLE OF line2 WITH EMPTY KEY.
DATA itab1 TYPE ty_itab1.
DATA itab2 TYPE ty_itab2.
METHODS fill_tables.
ENDCLASS.
CLASS ltc_app IMPLEMENTATION.
METHOD fill_tables.
itab1 = VALUE #(
( col1 = 'a11'
col2 = 'a12'
col3 = VALUE #( ( col1 = 'a11' col2 = VALUE #( ( col1 = 'a11' col2 = 'a12' )
( col1 = 'a21' col2 = 'a22' ) ) )
( col1 = 'a21' col2 = VALUE #( ( col1 = 'a11' col2 = 'a12' )
( col1 = 'a21' col2 = 'a22' ) ) ) ) )
( col1 = 'b21'
col2 = 'b22'
col3 = VALUE #( ( col1 = 'b11' col2 = VALUE #( ( col1 = 'b11' col2 = 'b12' )
( col1 = 'b21' col2 = 'b22' ) ) )
( col1 = 'b21' col2 = VALUE #( ( col1 = 'b11' col2 = 'b12' )
( col1 = 'b21' col2 = 'b22' ) ) ) ) )
( col1 = 'c31'
col2 = 'c32'
col3 = VALUE #( ( col1 = 'c11' col2 = VALUE #( ( col1 = 'c11' col2 = 'c12' )
( col1 = 'c21' col2 = 'c22' ) ) )
( col1 = 'c21' col2 = VALUE #( ( col1 = 'c11' col2 = 'c12' )
( col1 = 'c21' col2 = 'c22' ) ) ) ) ) ).
itab2 = VALUE #(
( col2 = 'x11'
col3 = VALUE #( ( col3 = 'x12' col2 = VALUE #( ( col2 = 'x12' )
( col2 = 'x22' ) ) )
( col3 = 'x22' col2 = VALUE #( ( col2 = 'x12' )
( col2 = 'x22' ) ) )
( col3 = 'x32' col2 = VALUE #( ( col2 = 'x12' )
( col2 = 'x22' ) ) ) )
col4 = 'x12' )
( col2 = 'y21'
col3 = VALUE #( ( col3 = 'y12' )
( col3 = 'y22' )
( col3 = 'y32' ) )
col4 = 'y22' ) ).
ENDMETHOD.
METHOD test.
data itab2_custom type ty_itab2.
data itab2_standard type ty_itab2.
fill_tables( ).
lcl_move_corresponding_nested=>process( EXPORTING source = itab1
IMPORTING target = itab2_custom ).
MOVE-CORRESPONDING itab1 TO itab2_standard EXPANDING NESTED TABLES.
cl_abap_unit_assert=>assert_equals( act = itab2_custom
exp = itab2_standard ).
ENDMETHOD.
METHOD test_2.
TYPES ty_itab2 TYPE STANDARD TABLE OF string WITH EMPTY KEY.
DATA itab1 TYPE TABLE OF string WITH EMPTY KEY.
DATA itab2_custom TYPE ty_itab2.
DATA itab2_standard TYPE ty_itab2.
itab1 = VALUE #( ( `A` ) ).
lcl_move_corresponding_nested=>process( EXPORTING source = itab1
IMPORTING target = itab2_custom ).
MOVE-CORRESPONDING itab1 TO itab2_standard EXPANDING NESTED TABLES.
cl_abap_unit_assert=>assert_equals( act = itab2_custom
exp = itab2_standard ).
ENDMETHOD.
METHOD test_3.
TYPES:
BEGIN OF ty_struct1,
a TYPE STANDARD TABLE OF string WITH EMPTY KEY,
END OF ty_struct1.
TYPES:
BEGIN OF ty_struct2,
a TYPE i,
END OF ty_struct2.
DATA struct1 TYPE ty_struct1.
DATA struct2_custom TYPE ty_struct2.
DATA struct2_standard TYPE ty_struct2.
FIELD-SYMBOLS <struct2_standard> TYPE any.
" MOVE-CORRESPONDING struct1 TO struct2_standard EXPANDING NESTED TABLES.
" Syntax error: "The identically named component "STRUCT1[]-TY_STRUCT1-A"
" cannot be converted to "STRUCT2_STANDARD[]-TY_STRUCT2-A".
"
" ASSIGN struct2_standard TO <struct2_standard>.
" MOVE-CORRESPONDING struct1 TO <struct2_standard> EXPANDING NESTED TABLES.
" Short dump: OBJECTS_MOVE_NOT_SUPPORTED
" Conversion of type "TABLE OF STRING" to type "I" not supported.
TRY.
lcl_move_corresponding_nested=>process( EXPORTING source = struct1
IMPORTING target = struct2_custom ).
cl_abap_unit_assert=>fail( msg = 'should have failed' ).
CATCH lcx_move_corresponding_nested ##NO_HANDLER.
ENDTRY.
ENDMETHOD.
ENDCLASS.