When interfacing between two SAP systems, you need to synchronize the data structure. Sometimes this data structure is a complex structure of nested table/structure and data elements. Usually this definition of a complex data structure is hard coded on both systems, and programs need to be hard coded to accommodate this definition of the data structure to enable data transfer.
More complex types of data structures require more data-structure dependent programs. This brings inflexibility in development, high maintenance, and inefficiency in development. Since you can pass the definition of simple data types from the source system to the target system with generic programming, you can disassemble the definition of a complex data structure into multiple instances of simple data types in a designated sequence. In each instance, you pass a simple data type definition to the target system. In the target/receiving system, you reassemble these data type definitions to build a complex data structure following the sequence.
This generic design greatly improves the code efficiency in interface development and is easy to maintain in future.
Let me define a complex data type, by which I mean a nested data structure, as shown in Figure 1.
Definition of complex structure ts_rec
Type TS_COMP is a structure consisting of a four-digit characteristic compcode and a string loc. Then structure type ts_rec is made of a string name, a structure of the type TS_COMP, and a table member of the type uja_t_dim_member.
To have a better understanding of the complex data structure type ts_rec, let’s visualize it. I declare a table dt_rec, which is a table of the structure type ts_rec. Further I populate the table DT_REC with two records. Now it looks like what you see in debug mode in Figure 2.
Table DT_REC is defined as table of structure type TS_REC
Double-click DT_REC in Figure 2 to go to Figure 3. You can see this table with the details of the two records (Figure 3).
Details of the two records
The field in the Name [CString] column has the value Simulation. The field in the COMP [Deep Structure] column is a structure. The field in the MEMBER [Internal Table] column is a table, so you need to expand COMP field of the first record by double-clicking Structure: deep in the first row to see details in Figure 4. You see the fields and corresponding values for the COMP structure of the first record.
Value of the COMP structure of the first record
The fields and corresponding values for the COMP structure of the second record are shown in Figure 5.
Value of the comp structure of the second record
Figure 6 shows the values of the member for the first record. According to Figure 3, MEMBER is the third field of the structure. MEMBER is a table of two records, shown in Figure 6. Here I gave the value of MBR_11 as the first record of this table MEMBER and value MBR_12 as the second record of this table MEMBER.
Values of the member field of first record
Figure 7 shows the value of the member for the second record.
Value of the MEMBER field of the second record
If the content could be displayed in a spreadsheet, it would look like Figure 8.
Flat display of the two records in table DT_REC
How do you pass the definition of this example of a complex data structure to the target system? This article is not about how to send the two records to the calling system. Instead, it is about how to send the definition of ts_rec to the calling system so that the calling system can rebuild the structure, waiting for the data (i.e., the two records) to fill in the structure.
I am going to use type abap_compdescr to store the definition of this complex structure.
Figure 9 is the definition of type abap_compdescr.
Definition of abap_compdescr
The approach is to check each component of the structure. Here, for example, the structure type ts_rec. If it is data element, you get the definition into abap_compdescr. If it is a structure, you disassemble it into a list of components.
If it is a table, you get the line type of the table and check the components of this line type. In this way, you can find if the component is a structure as well (i.e., if it is a nested structure, you can run this function recursively until you get a component of predefined ABAP types). If you find the component of the table line type is a structure or another table, you run it recursively until you get the predefined ABAP types (i.e., the lowest level of data types that is defined by any SAP system.
Figure 10 shows an example of how to get the definition of structure1 into a list of data definitions. Structure1 has two components: comp1 and comp2. Comp1 is a single element of a predefined ABAP type, so you record it as the first data definition. Comp2 is made up of two components: comp21 and comp22. You store this as a second data definition. From comp21 you get the definition of the element as a predefined ABAP type. Then store this as a third data definition. You then look into comp22 to understand it is a table. This is stored as the fourth data definition. Get the line type of the table. From this line type you then get a list of the components of this line type. Looking into these components one by one, you get a definition and store them as the fifth data definition, sixth data definition, and so on, and eventually you get a list of data definitions.
Downgrade from a table to a structure to an element
To implement this, with possibly infinite layers of this hierarchical presentation of Figure 10, you have to define a generic function that can call it recursively to accomplish the goal.
Here is the approach:
1. From the data get a definition of the structure through method cl_abap_structdescr=>describe_by_data( ) and get a list of components through method cl_abap_structdescr->get_components( ). In Figure 11, it is represented by lr_struct->get_components( ). Then loop through them to get a definition of each component through method get_elem( ). (This method is called in Figure 11, and implementation of this method is in Figure 12.)
Get components from the structure and loop through the components
With the data in table lt_rec, you get a line of lt_rec as ls_rec. You get definition of the line type of lt_rec into lr_struct by cl_abap_structdescr=>describe_by_data( ). Get the components of lt_rec into lr_struct->components. Then check each component, one by one in the loop.
- If it is an element, you call method get_elem( ).
- If it is a structure, you call method get_struct( ).
- If it is a table, you call method get_table( ).
2. In method get_elem( ), check if it is a character, string, or some other element to determine what information needs to be appended to the data definition table dt_components.
If the element is a structure, call method get_struct( ). This is a recursive call. You don’t rewrite another method for getting a structure definition. You can reuse the method get_structure( ).
Figure 12 shows the implementation of method get_elem( ). You are checking the element type. If it is a predefined ABAP type, append it to ct_components. The ct_components is what I referred as a list of data definitions. If it is a structure, call the recursive function to disassemble it again to a list of components, then call method get_elem( ) for each component.
Content of method get_elem( )
3. In method get_struct( ), check to see if the component is an element, a structure, or a table.
Figure 13 shows if you run the get_struct( ) method, you get a list of components through the get_components( ) method. Then loop through these components. If it is an element, call get_elem( ). If it is a structure, call method get_struct( ) recursively. If it is table, call method get_table( ).
Content of method get_struct( ).
Here you can see only the type element goes to the method get_element( ), which ends this journey and returns it back. For the component of the type structure or type table, it goes to method get_struct( ) or method get_table( ). This call stack shows it is a recursive nested call until it reaches the type element.
Similar to the method get_struct( ), the method get_table has the same behavior except it needs to get the line type of the table, which is a structure. Once you disassemble this structure to a list of components and get a definition of each of the components, you just need to mark this one as a table and all these derived lists of data definitions refer to this table. Figure 14 explains the detail implementation of method get_table( ).
Content of method get_table( )
4. Therefore, by the end of the program, you get the data definition in a table of the type abap_compdescr as shown in Figure 15.
Type definition of complex structure TS_REC
Comparing Figure 15 against Figure 1 for the definition of TS_REC, you have this information:
Figure 15 is the list of data definitions and it is a flat list of the data definition of a complex, hierarchical, two-layer data structure.
For the type_kind g, or type_kind c, create a data element with an appropriate length (with decimals if it is a key figure).
For the type_kind v, which is a structure, create a structure, the components of which have the structure name as a prefix separated by a hyphen as shown in Figure 15, line 3 of table lt_comp, field name ‘COMP-COMPCODE’.
For the type_kind h, which is a table, create a table, the components of which have the table name as the prefix separated by a hyphen (-). In the example in Figure 15, the component name is blank, so you know this is a table of an element without a structure involved.
You can pass the definition of the complex data type to the calling system (e.g., here the actual parameter is LT_COMP of the type table abap_compdescr). The calling system is able to create the complex structure following rules in Figure 15.