ABAP Deep Dive - CORRESPONDING
In this article, a little more about the new Corresponding Statement and how to use it in detail. Let's take a look at the additional features.
Table of contents
We already discussed the new statement in an older article and explained some of its advantages. In this article, we want to look at some new facets and how you can make the most of them. We have also noticed that developers usually do not use the full potential of the statements to save on coding. In this context, we want to look at some innovations and special features.
Introduction
The new CORRESPONDING is a constructor expression, which means it creates a new element from its source object. Here you can imagine it in such a way that a new element is created for the target, is empty and then the assignment is carried out according to the corresponding rules. The values are copied and the source object is not changed. This has the nice advantage that you save yourself the clear within a loop, for example, if the loop structure is assigned to a new structure for processing.
Preparation
For the following examples we define separate structures and table types that we want to use. There is always a source structure and a target structure in which some field names are the same and some are different. The entire example below in the article will give you the entire example.
TYPES:
td_text TYPE c LENGTH 25,
td_number TYPE i,
td_long TYPE string,
BEGIN OF ts_source,
text1 TYPE td_text,
text3 TYPE td_text,
num1 TYPE td_number,
longtext TYPE td_long,
END OF ts_source,
tt_source TYPE STANDARD TABLE OF ts_source WITH EMPTY KEY,
BEGIN OF ts_target,
ident TYPE td_number,
num TYPE td_number,
longtext TYPE td_long,
text1 TYPE td_text,
text2 TYPE td_text,
END OF ts_target,
tt_target TYPE STANDARD TABLE OF ts_target WITH EMPTY KEY,
tt_target_key TYPE SORTED TABLE OF ts_target WITH UNIQUE KEY ident,
BEGIN OF ts_source_nested,
field1 TYPE td_text,
sub TYPE ts_source,
END OF ts_source_nested,
BEGIN OF ts_target_nested,
field TYPE td_text,
sub TYPE ts_target,
END OF ts_target_nested.
A simple MOVE of the structures therefore looks like this, only the components with the same name are moved, leaving the target structure relatively empty:
DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source ).
io_out->write( |Simple move:| ).
io_out->write( ls_target ).
MAPPING
When using a mapping, components that do not have the same name can also be moved, whereby the source and target fields are specified in the mapping. The Content Assist (CTRL + SPACE) is also available in Eclipse for better help:
DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source MAPPING text2 = text3 num = num1 ).
io_out->write( |Move with mapping:| ).
io_out->write( ls_target ).
The output now looks like this, the remaining and existing fields have now been successfully mapped and assigned to the target structure:
EXCEPT
Sometimes fields should be deleted after the assignment, then when it comes to further processing or the fields have to be empty because they are no longer needed or can lead to problems. In the past, after the assignment, the corresponding fields were cleared. You can save yourself this with the EXCEPT addition, since this ensures that the fields are not transferred to the target structure:
DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source MAPPING text2 = text3 num = num1 EXCEPT longtext ).
io_out->write( |Move without longtext:| ).
io_out->write( ls_target ).
In the example above, we did the same mapping as before, but this time we don't want to copy the long text. The target structure now looks like this:
DISCARDING DUPLICATES
There are cases where a standard table should be converted into a sorted table with a key. Here, however, you have to be sure that the key only exists once in the source table, otherwise an exception will be raised and processing will be aborted. In the past you could do this with multiple statements (sorting the table and removing the duplicates). In this example we fill the table unsorted and with a duplicate and use DISCARDING DUPLICATES in the assignment, so the duplicates are removed and no exception is thrown:
DATA(lt_source) = VALUE tt_source(
( num1 = 14 text1 = 'Bread' )
( num1 = 3 text1 = 'Butter' )
( num1 = 7 text1 = 'Jam' )
( num1 = 14 text1 = 'Salt' )
( num1 = 11 text1 = 'Egg' )
( num1 = 19 text1 = 'Coffee' )
).
DATA(lt_target) = CORRESPONDING tt_target_key( lt_source DISCARDING DUPLICATES MAPPING ident = num1 ).
io_out->write( |Move table with key:| ).
io_out->write( lt_target ).
We map the number field to the key accordingly and remove the duplicates. The first entry in each case is transferred to the target table and the result looks like this:
Nested Mapping
What about nested structures? This involves structures that map another structure or table at field level and thus have several levels. Here you can also apply the mapping, as we have already done above. If you then want to address the deep structure, you have to put the element in brackets and do your own mapping there:
DATA(ls_source) = VALUE ts_source_nested(
field1 = 'Sub structure'
sub = fill_structure( )
).
DATA(ls_target) = CORRESPONDING ts_target_nested( ls_source
MAPPING field = field1
( sub = sub MAPPING text2 = text3 num = num1 )
).
io_out->write( |Nested move:| ).
io_out->write( ls_target-field ).
io_out->write( ls_target-sub ).
In the example we have mapped the main field and opened another mapping for the deep structure. The output must be done in two steps because the output method does not support deep structures:
Entire example
As always, you can find the complete example here in the form of an executable ABAP class. The individual examples have been moved to individual methods to ensure better readability:
CLASS zcl_bs_demo_corresponding_deep DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES:
td_text TYPE c LENGTH 25,
td_number TYPE i,
td_long TYPE string,
BEGIN OF ts_source,
text1 TYPE td_text,
text3 TYPE td_text,
num1 TYPE td_number,
longtext TYPE td_long,
END OF ts_source,
tt_source TYPE STANDARD TABLE OF ts_source WITH EMPTY KEY,
BEGIN OF ts_target,
ident TYPE td_number,
num TYPE td_number,
longtext TYPE td_long,
text1 TYPE td_text,
text2 TYPE td_text,
END OF ts_target,
tt_target TYPE STANDARD TABLE OF ts_target WITH EMPTY KEY,
tt_target_key TYPE SORTED TABLE OF ts_target WITH UNIQUE KEY ident,
BEGIN OF ts_source_nested,
field1 TYPE td_text,
sub TYPE ts_source,
END OF ts_source_nested,
BEGIN OF ts_target_nested,
field TYPE td_text,
sub TYPE ts_target,
END OF ts_target_nested.
PROTECTED SECTION.
PRIVATE SECTION.
METHODS:
fill_structure
RETURNING VALUE(rs_source) TYPE ts_source,
move_simple_structure
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
move_with_mapping
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
move_without_fields
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
move_duplicate_tables
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out,
move_nested_structure
IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_corresponding_deep IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
move_simple_structure( out ).
move_with_mapping( out ).
move_without_fields( out ).
move_duplicate_tables( out ).
move_nested_structure( out ).
ENDMETHOD.
METHOD fill_structure.
rs_source = VALUE ts_source(
text1 = 'Some value'
text3 = 'New values'
num1 = 12
longtext = `This is a very long ABAP string in a structure field`
).
ENDMETHOD.
METHOD move_simple_structure.
DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source ).
io_out->write( |Simple move:| ).
io_out->write( ls_target ).
ENDMETHOD.
METHOD move_with_mapping.
DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source MAPPING text2 = text3 num = num1 ).
io_out->write( |Move with mapping:| ).
io_out->write( ls_target ).
ENDMETHOD.
METHOD move_without_fields.
DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source MAPPING text2 = text3 num = num1 EXCEPT longtext ).
io_out->write( |Move without longtext:| ).
io_out->write( ls_target ).
ENDMETHOD.
METHOD move_duplicate_tables.
DATA(lt_source) = VALUE tt_source(
( num1 = 14 text1 = 'Bread' )
( num1 = 3 text1 = 'Butter' )
( num1 = 7 text1 = 'Jam' )
( num1 = 14 text1 = 'Salt' )
( num1 = 11 text1 = 'Egg' )
( num1 = 19 text1 = 'Coffee' )
).
DATA(lt_target) = CORRESPONDING tt_target_key( lt_source DISCARDING DUPLICATES MAPPING ident = num1 ).
io_out->write( |Move table with key:| ).
io_out->write( lt_target ).
ENDMETHOD.
METHOD move_nested_structure.
DATA(ls_source) = VALUE ts_source_nested(
field1 = 'Sub structure'
sub = fill_structure( )
).
DATA(ls_target) = CORRESPONDING ts_target_nested( ls_source
MAPPING field = field1
( sub = sub MAPPING text2 = text3 num = num1 )
).
io_out->write( |Nested move:| ).
io_out->write( ls_target-field ).
io_out->write( ls_target-sub ).
ENDMETHOD.
ENDCLASS.
Conclusion
The new statement is more powerful than you might think. Together with the older article on CORRESPONDING, you get the full overview of the new statement and how you can use it sensibly.