旧版本 ABAP 上扩展嵌套表的替代方案?

问题描述 投票:0回答:1

正如人们可能知道的那样,我们有这样一个方便的 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

structure abap internal-tables rtts
1个回答
1
投票

如果您使用 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.
© www.soinside.com 2019 - 2024. All rights reserved.