diff --git a/06_Dynamic_Programming.md b/06_Dynamic_Programming.md index dba31bc..c096930 100644 --- a/06_Dynamic_Programming.md +++ b/06_Dynamic_Programming.md @@ -1,2177 +1,2176 @@ - - -# Dynamic Programming - -- [Dynamic Programming](#dynamic-programming) - - [Introduction](#introduction) - - [Excursion: Field Symbols and Data References](#excursion-field-symbols-and-data-references) - - [Field Symbols](#field-symbols) - - [Data References](#data-references) - - [Dynamic ABAP Statements](#dynamic-abap-statements) - - [Dynamic ASSIGN Statements](#dynamic-assign-statements) - - [Dynamically Specifying Data Types/Creating (Data) Objects](#dynamically-specifying-data-typescreating-data-objects) - - [Accessing Structure Components Dynamically](#accessing-structure-components-dynamically) - - [Dynamic Specifications in Statements for Processing Internal Tables](#dynamic-specifications-in-statements-for-processing-internal-tables) - - [Dynamic ABAP SQL Statements](#dynamic-abap-sql-statements) - - [Dynamic Invoke](#dynamic-invoke) - - [Validating Input for Dynamic Specifications (CL\_ABAP\_DYN\_PRG)](#validating-input-for-dynamic-specifications-cl_abap_dyn_prg) - - [Runtime Type Services (RTTS)](#runtime-type-services-rtts) - - [Getting Type Information at Runtime](#getting-type-information-at-runtime) - - [Dynamically Creating Data Types at Runtime](#dynamically-creating-data-types-at-runtime) - - [Dynamically Creating Data Objects at Runtime](#dynamically-creating-data-objects-at-runtime) - - [More Information](#more-information) - - [Executable Example](#executable-example) - -## Introduction - -- Regarding "dynamic" in contrast to "static" aspects, [ABAP programs](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_program_glosry.htm) can include both dynamic and static parts. -- Consider a [data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_object_glosry.htm "Glossary Entry") in your program: - - It can be declared as a [static data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstatic_data_object_glosry.htm), i. e. you provide all attributes by specifying the [data type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_type_glosry.htm) and more statically in the code. - - ```abap - "Internal table declaration - DATA itab TYPE TABLE OF zdemo_abap_carr WITH EMPTY KEY. - ``` - - - The name `itab` of the data object is determined at compile time and remains stable throughout the execution of the program. -- However, there can also be use cases where the attributes of such a data object are not statically determined. This is where dynamic aspects enter the picture: Attributes, names, types etc. are not determined at compile time but rather at runtime. -- There are ABAP statements that include these dynamic aspects in the syntax. Assume you have a simple program and a UI that includes an input field storing the input in a data object named `dbtab`. As input, you expect the name of a database table to be provided. In the end, you want to retrieve all entries of the database table and store them in an internal table. This table should be displayed. So, there is random input at runtime and your program must be able to deal with it. - - See the following `SELECT` statement. The `FROM` clause does not include a statically defined table to be selected from. Instead, there is a pair of parentheses including a data object. It is a character-like data object. Assume the data object holds the name of the database table. At runtime, the data retrieval happens from the database table that was inserted in the input field. - - ```abap - DATA(dbtab) = `ZDEMO_ABAP_FLI`. - - SELECT * - FROM (dbtab) - INTO TABLE @DATA(some_itab). - ``` - -- Further aspects for dynamic programming in ABAP enter the picture if you want to determine information about data types and data objects at runtime ([RTTI](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm)) or even create them ([RTTC](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_creation_glosry.htm)). - -- In general, dynamic programming also comes with some downsides. For example, the ABAP compiler cannot check the dynamic programming feature like the `SELECT` statement mentioned above. There is no syntax warning or suchlike (note the `CL_ABAP_DYN_PRG` class that supports dynamic programming). The checks are performed only at runtime, which has an impact on the performance. Plus, the testing of [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") -that include dynamic programming features may be difficult. - - -

⬆️ back to top

- -## Excursion: Field Symbols and Data References - -[Field symbols](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfield_symbol_glosry.htm "Glossary Entry") -and [data references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_glosry.htm "Glossary Entry") are covered here since they are supporting elements for dynamic programming. - -### Field Symbols - -Field symbols ... - -- are symbolic names for almost any data object or parts of existing data objects. -- can be assigned actual memory areas at program runtime (using `ASSIGN`). Note that you can only work with the field symbols if indeed they have been assigned before. -- can be used as placeholders for a data object at an [operand position](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenoperand_position_glosry.htm). - - Consider there is a data object in your program. A field symbol is also available that is assigned the memory area of this data object. Accessing a field symbol is like accessing the [named data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abennamed_data_object_glosry.htm) or part of the object itself. -- do not reserve physical space in the [data area](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_area_glosry.htm) of a program like a data object. Instead, they work as dynamic identifiers of a memory area in which a specific data object or part of an object is located. -- can be typed either with [generic data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abengeneric_data_type_glosry.htm "Glossary Entry") or [complete data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencomplete_data_type_glosry.htm "Glossary Entry"). -- are declared using the statement [`FIELD-SYMBOLS`](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapfield-symbols.htm) or the [declaration operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendeclaration_operator_glosry.htm) [`FIELD-SYMBOL`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfield-symbol_inline.htm). Their names must be included between angle brackets. - -**Declaring field symbols** - -Syntax: -``` abap -"Declaring field symbols using the FIELD-SYMBOLS statement -"and providing a complete/generic type - -"Examples for complete types -FIELD-SYMBOLS: TYPE i, - TYPE zdemo_abap_fli, - TYPE LINE OF some_table_type, - LIKE some_data_object. - -"Examples for generic types (see more examples further down) -FIELD-SYMBOLS TYPE c. "Text field with a generic length -FIELD-SYMBOLS TYPE csequence. "Text-like (c, string) -FIELD-SYMBOLS TYPE data. "Any data type -FIELD-SYMBOLS TYPE any table. "Internal table with any table type - -"Declaring field symbols inline -"In an inline declaration, the typing of the field symbol is done -"with the generic type data. -"Example use case: Inline declaration of a field symbol for an internal table. -LOOP AT itab ASSIGNING FIELD-SYMBOL(). - ... -ENDLOOP. -``` - -> **💡 Note**
->- After its declaration, a field symbol is initial, i. e. a memory area is not (yet) assigned to it (apart from the inline declaration). If you use an unassigned field symbol, an exception is raised. ->- There are plenty of options for generic ABAP types. A prominent one - is `data` that stands for any data type. See more information in the - topic [Generic ABAP - Types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbuilt_in_types_generic.htm) and in a code snippet below. ->- Field symbols cannot be declared in the declaration part of - [classes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclass_glosry.htm "Glossary Entry") - and - [interfaces](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenoo_intf_glosry.htm "Glossary Entry"). - -**Assigning data objects** - -[`ASSIGN`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapassign.htm) -statements assign the memory area of a data object to a field symbol. -Once the memory area is assigned, you can work with the content. - -``` abap -"Some data object declarations to be used -DATA: num TYPE i, - struc TYPE zdemo_abap_fli, "Demo database table - itab_str TYPE string_table, - itab_fli TYPE TABLE OF zdemo_abap_fli WITH EMPTY KEY. -APPEND INITIAL LINE TO itab_fli. - -"Declaring field symbols with complete types -FIELD-SYMBOLS: TYPE i, - TYPE zdemo_abap_fli, - TYPE string_table. - -"Declaring field symbols with generic type -FIELD-SYMBOLS TYPE data. - -"Assigning data objects to field symbols -"Using field symbols with a static type -ASSIGN num TO . -ASSIGN struc TO . -ASSIGN itab_str TO . -"Using field symbol with a generic type -ASSIGN num TO . -ASSIGN itab_fli TO . -ASSIGN itab_fli[ 1 ] TO . -"Assigning components -ASSIGN struc-carrid TO . -ASSIGN itab_fli[ 1 ]-connid TO . - -"Inline declaration (the field symbol has the type data) -ASSIGN num TO FIELD-SYMBOL(). - -"CASTING addition for matching types of data object and field -"symbol when assigning memory areas -TYPES c_len_3 TYPE c LENGTH 3. -DATA(chars) = 'abcdefg'. - -FIELD-SYMBOLS TYPE c_len_3. - -"Implicit casting -ASSIGN chars TO CASTING. "abc - -FIELD-SYMBOLS TYPE data. - -"Explicit casting -ASSIGN chars TO CASTING TYPE c_len_3. "abc - -DATA chars_l4 TYPE c LENGTH 4. -ASSIGN chars TO CASTING LIKE chars_l4. "abcd -``` - -> **💡 Note**
-> - If you use an unassigned field symbol, an exception is raised. Before using it, you can check the - assignment with the following logical expression. The statement is true if the field symbol is assigned. -> ``` abap -> IF IS ASSIGNED. ->   ... -> ENDIF. -> -> DATA(check) = COND #( WHEN IS ASSIGNED THEN `assigned` ELSE `not assigned` ). -> ``` ->- Using the statement `UNASSIGN`, you can explicitly remove the assignment of the field symbol. A `CLEAR` statement only initializes the value. -> ``` abap -> UNASSIGN . -> ``` ->- See more information on the addition `CASTING` [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapassign_casting.htm). - -**Examples using field symbols** - -``` abap -"Assignments -DATA num TYPE i VALUE 1. -FIELD-SYMBOLS TYPE i. -ASSIGN num TO . - - = 2. -"The data object 'num' has now the value 2. - -"Loops -"Here, field symbols are handy since you can avoid an -"actual copying of the table line. -SELECT * - FROM zdemo_abap_fli - INTO TABLE @DATA(itab). - -FIELD-SYMBOLS LIKE LINE OF itab. - -LOOP AT itab ASSIGNING . - -carrid = ... "The field symbol represents a line of the table. - -connid = ... "Components are accessed with the component selector. - "Here, it is assumed that a new value is assigned. - ... -ENDLOOP. - -"Inline declaration of a field symbol. The field symbol is implcitly typed -"with the generic type data. -LOOP AT itab ASSIGNING FIELD-SYMBOL(). - -carrid = ... - -connid = ... - ... -ENDLOOP. - -"----------- Generic typing ----------- -"- Generic types are available with which formal parameters of methods or field symbols -" can be specified. -"- At runtime, the actual data type is copied from the assigned actual parameter or -" memory area, i.e. they receive the complete data type only when an actual parameter -" is passed or a memory area is assigned. - -"The following code snippet demonstrates generic types with field symbols. -FIELD-SYMBOLS: - "Any data type - TYPE data, - TYPE any, - "Any data type can be assigned. Restrictions for formal parameters and 'data': no - "numeric functions, no description functions, and no arithmetic expressions can be - "passed to these parameters. However, you can bypass the restriction by applying the - "CONV operator for the actual parameter. - - "Character-like types - TYPE c, "Text field with a generic length - TYPE clike, "Character-like (c, n, string, d, t and character-like flat structures) - TYPE csequence, "Text-like (c, string) - TYPE n, "Numeric text with generic length - TYPE x, "Byte field with generic length - TYPE xsequence, "Byte-like (x, xstring) - - "Numeric types - TYPE decfloat, "decfloat16, decfloat34) - TYPE numeric, "Numeric ((b, s), i, int8, p, decfloat16, decfloat34, f) -

TYPE p, "Packed number (generic length and number of decimal places) - - "Internal table types - TYPE ANY TABLE, "Internal table with any table type - TYPE HASHED TABLE, - TYPE INDEX TABLE, - TYPE SORTED TABLE, - TYPE STANDARD TABLE, - TYPE table, "Standard table - - "Other types - TYPE simple, "Elementary data type including enumerated types and - "structured types with exclusively character-like flat components - TYPE REF TO object. "object can only be specified after REF TO; can point to any object - -"Data objects to work with -DATA: BEGIN OF s, - c3 TYPE c LENGTH 3, - c10 TYPE c LENGTH 10, - n4 TYPE n LENGTH 4, - str TYPE string, - time TYPE t, - date TYPE d, - dec16 TYPE decfloat16, - dec34 TYPE decfloat34, - int TYPE i, - pl4d2 TYPE p LENGTH 4 DECIMALS 2, - tab_std TYPE STANDARD TABLE OF string WITH EMPTY KEY, - tab_so TYPE SORTED TABLE OF string WITH NON-UNIQUE KEY table_line, - tab_ha TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line, - xl1 TYPE x LENGTH 1, - xstr TYPE xstring, - structure TYPE zdemo_abap_carr, "character-like flat structure - oref TYPE REF TO object, - END OF s. - -"The following static ASSIGN statements demonstrate various assignments -"Note: -"- The statements commented out show impossible assignments. -"- If a static assignment is not successful, sy-subrc is not set and no -" memory area is assigned. Dynamic assignments, however, set the value. - -"----- Any data type ----- -ASSIGN s-c3 TO . -ASSIGN s-time TO . -ASSIGN s-tab_std TO . -ASSIGN s-xstr TO . -ASSIGN s-pl4d2 TO . -ASSIGN s-date TO . -ASSIGN s TO . - -"----- Character-like types ----- -ASSIGN s-c3 TO . -ASSIGN s-c10 TO . -"ASSIGN s-str TO . - -ASSIGN s-c10 TO . -ASSIGN s-str TO . -ASSIGN s-n4 TO . -ASSIGN s-date TO . -ASSIGN s-time TO . -ASSIGN s-structure TO . - -ASSIGN s-c10 TO . -ASSIGN s-str TO . -"ASSIGN s-n4 TO . - -ASSIGN s-n4 TO . -"ASSIGN s-int TO . -"ASSIGN s-time TO . - -ASSIGN s-xl1 TO . -"ASSIGN s-xstr TO . - -ASSIGN s-xl1 TO . -ASSIGN s-xstr TO . - -"----- Numeric types ----- -ASSIGN s-dec16 TO . -ASSIGN s-dec34 TO . -ASSIGN s-int TO . -ASSIGN s-pl4d2 TO . -"ASSIGN s-n4 TO . - -ASSIGN s-dec16 TO . -ASSIGN s-dec34 TO . - -ASSIGN s-pl4d2 TO

. -"ASSIGN s-dec34 TO

. - -"----- Internal table types ----- -ASSIGN s-tab_std TO . -ASSIGN s-tab_so TO . -ASSIGN s-tab_ha TO . - -ASSIGN s-tab_std TO . -ASSIGN s-tab_so TO . -"ASSIGN s-tab_ha TO . - -"ASSIGN s-tab_std TO . -ASSIGN s-tab_so TO . -"ASSIGN s-tab_ha TO . - -ASSIGN s-tab_std TO . -ASSIGN s-tab_std TO

. -"ASSIGN s-tab_so TO . -"ASSIGN s-tab_so TO
. -"ASSIGN s-tab_ha TO . -"ASSIGN s-tab_ha TO
. - -"ASSIGN s-tab_std TO . -"ASSIGN s-tab_so TO . -ASSIGN s-tab_ha TO . - -"----- Other types ----- -ASSIGN s-c10 TO . -ASSIGN s-str TO . -ASSIGN s-dec34 TO . -ASSIGN s-date TO . -ASSIGN s-structure TO . -ASSIGN s-xl1 TO . -"ASSIGN s-tab_ha TO . - -ASSIGN s-oref TO . -s-oref = NEW zcl_demo_abap_objects( ). -``` - -

⬆️ back to top

- -### Data References - -[Data references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_glosry.htm "Glossary Entry") -... - -- are references that point to any data object or to their parts (for example, components, lines of internal tables). -- are contained in [data reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_variable_glosry.htm "Glossary Entry") - in ABAP programs. - -[Data reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_variable_glosry.htm "Glossary Entry") -... - -- are data objects that contain a reference. -- are "opaque", i. e. the contained references cannot be accessed directly. To access the content, these variables must be dereferenced first. -- are [deep](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendeep_glosry.htm "Glossary Entry") data objects like strings and internal tables. -- are typed with the addition [`REF TO`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abaptypes_references.htm) followed by a [static type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstatic_type_glosry.htm). Note the [dynamic type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendynamic_type_glosry.htm) in this context: The dynamic type of such a variable is the data type to which it actually points. This concept is particularly relevant in the context of assignments (see the assignment rules [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconversion_references.htm)). -- can be typed with a complete or generic type. However, only `data` can be used as generic type. - -> **💡 Note**
-> [Object references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_reference_glosry.htm "Glossary Entry") -and [object reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_refer_variable_glosry.htm "Glossary Entry") are not part of this cheat sheet. To get more details, refer to the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_reference_type.htm) or the cheat sheet [ABAP Object Orientation](04_ABAP_Object_Orientation.md). - -**Declaring data reference variables** - -``` abap -"Example declarations of data reference variables with static types. -"The static types can be complete or generic (but only data can be used). -"Note that they do not yet point to a data object. At this stage, -"initial reference variables contain null references. -DATA: ref_a TYPE REF TO i, "Complete data type - ref_b TYPE REF TO some_dbtab, "Complete data type - ref_c LIKE REF TO some_data_object, - ref_d TYPE REF TO data, "Generic data type - ref_e LIKE ref_a. "Referring to an existing data reference variable -``` - -As shown below, instead of the explicit declaration, inline declarations are also possible. -See also the cheat sheet [Data Types and Data Objects](16_Data_Types_and_Objects.md). - -**Assigning references to existing data objects** using the -[reference operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenreference_operator_glosry.htm "Glossary Entry") -`REF`. -``` abap -"Declaring a data object -DATA num TYPE i VALUE 5. - -"Declaring data reference variables -DATA ref1 TYPE REF TO i. -DATA ref_gen TYPE REF TO data. - -"Creating data references to data objects. -"The # character stands for a data type that is determined in the -"following hierarchy: -"- If the data type required in an operand position is unique and -" known completely, the operand type is used. -"- If the operand type cannot be derived from the context, the -" data type of the data object within the parentheses is used. -"- If the data type of the data object within the parentheses is -" not known statically, the generic type data is used. - -ref1 = REF #( num ). -ref_gen = REF #( num ). - -"Creating a data reference variable inline. -"Note: No empty parentheses can be specified after REF. -DATA(ref2) = REF #( num ). - -"Data reference variable of type ref to data by specifying the -"generic type data after REF -DATA(ref3) = REF data( ... ). - -"A non-generic type can be used; only if an upcast works (see -"upcasts below) -DATA(ref3) = REF some_type( ... ). - -"The older syntax GET REFERENCE having the same effect should -"not be used anymore. -"GET REFERENCE OF num INTO ref1. -"GET REFERENCE OF num INTO DATA(ref5). -``` - -**Creating new data objects at runtime**: -[Anonymous data objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenanonymous_data_object_glosry.htm "Glossary Entry") ... -- are dynamically created at runtime. -- are relevant if the data type is only known when the program is executed. -- cannot be addressed by a name ("anonymous"). -- expect a data reference variable when declared. The content of an anonymous data object can only be accessed using dereferenced variables as shown below or field symbols. -- can be created using the statement [`CREATE DATA`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_data.htm), the instance operator [`NEW`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expression_new.htm), or the addition [`NEW`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_into_target.htm) of the `INTO` clause in a `SELECT` statement. - -> **💡 Note**
-> The following snippet covers statically defined types. Data objects can also be created with `CREATE DATA` dynamically using dynamic type definitions (the type name is specified within a pair of parentheses) and type description objects ([`TYPE HANDLE` addition](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm)) as shown further down. -> Using [`CREATE OBJECT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object.htm) statements, you can create an object as an instance of a class and assign the reference to the object to an [object reference variable](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_refer_variable_glosry.htm). Find more information in the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object.htm). - -```abap -"CREATE DATA statements -"Note that there are many additions available. The examples -"show a selection. Behind TYPE and LIKE, the syntax offers -"the same possibilities as the DATA statement. - -"Creating an anonymous data object with an implicit type. -"If neither of the additions TYPE or LIKE are specified, the -"data reference variable must be completely typed. -DATA dref_1 TYPE REF TO string. -CREATE DATA dref_1. - -"Creating anonymous data objects with explicit data type -"specification. -"Data reference variable with a generic type to be used in -"the following examples for the anonymous data object. -DATA dref_2 TYPE REF TO data. - -"Elementary, built-in ABAP type -CREATE DATA dref_2 TYPE p LENGTH 8 DECIMALS 3. - -"Anomyous internal table ... -"using the LIKE addition to refer to an existing internal table -DATA itab TYPE TABLE OF zdemo_abap_carr. -CREATE DATA dref_2 LIKE itab. - -"by specifying the entire table type -CREATE DATA dref_2 TYPE HASHED TABLE OF zdemo_abap_carr - WITH UNIQUE KEY carrid. - -"Anonymous structures -CREATE DATA dref_2 LIKE LINE OF itab. -CREATE DATA dref_2 TYPE zdemo_abap_carr. - -"Creating reference variable -CREATE DATA dref_2 TYPE REF TO itab. - -"NEW operator -"- Works like CREATE DATA dref TYPE type statements and can -" be used in general expression positions. -"- Allows to assign values to the new anonymous data objects -" in parentheses - -"Creating data reference variables -DATA: dref_3 TYPE REF TO i, - dref_4 TYPE REF TO data. - -"# character after NEW if the data type can be identified -"completely instead of the explicit type specification (only -"non-generic types possible) -dref_3 = NEW #( 123 ). -dref_3 = NEW i( 456 ). -dref_4 = NEW zdemo_abap_carr( ). "not assigning any values -dref_4 = NEW string( `hi` ). - -"Creating anonymous data objects inline -"In doing so, you can omit a prior declaration of a variable. -DATA(dref_5) = NEW i( 789 ). -DATA(dref_6) = NEW zdemo_abap_carr( carrid = 'AB' - carrname = 'AB Airlines' ). - -"ABAP SQL SELECT statements -"Using the NEW addition in the INTO clause, an anonymous data -"object can be created in place. -SELECT * - FROM zdemo_abap_carr - INTO TABLE NEW @DATA(dref_7). "internal table - -SELECT SINGLE * - FROM zdemo_abap_carr - INTO NEW @DATA(dref_8). "structure -``` - -**Assignments between two data reference variables**. As mentioned above regarding the assignment, note that static types of both data -reference variables must be compatible. As a result of an assignment, both the target reference variable and the source reference variable point to the same data object. - -Excursion: Static vs. dynamic type, upcasts and downcasts -- Data reference variables have ... - - a [static type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstatic_type_glosry.htm "Glossary Entry"). This is the type you specify when declaring the variable, i. e. `i` is the static type in this example: `DATA ref TYPE REF TO i.`. The static type can also be a generic data type: `DATA ref TYPE REF TO data.`. - - a [dynamic type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendynamic_type_glosry.htm "Glossary Entry"), the type of a data object to which the reference variable actually points to at runtime. -- For an assignment to work, the differentiation is particularly relevant since the following basic rule applies: The static type of the target reference variable must be more general than or the same as the dynamic type of the source reference variable. - -- This is where the concepts of [upcast](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenup_cast_glosry.htm "Glossary Entry") and [downcast](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendown_cast_glosry.htm "Glossary Entry") enter the picture. - - Up and down? This concept originates from the idea of moving up or down in an [inheritance tree](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninheritance_tree_glosry.htm). In an assignment between reference variables, the target variable inherits the dynamic type of the source variable. - - Upcast: If the static type of the target variables is **less specific or the same** as the static type of the source variable, an assignment is possible. This includes, for example, assignments with the [assignment operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenassignment_operator_glosry.htm) `=`. - - Downcast: If the static type of the target variable is **more specific** than the static type of the source variable, a check must be made at runtime before the assignment is done. If you indeed want to trigger such a downcast, you must do it explicitly in your code. You can do this, for example, using the - [constructor operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_operator_glosry.htm "Glossary Entry") -[`CAST`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expression_cast.htm). In older code, you may see the use of the [`?=`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmove_cast.htm) operator. - - In contrast to a downcast, an upcast does not have to be done explicitly. However, you can - but need not - use the mentioned operators for upcasts, too. - - -``` abap -"Examples demonstrating up- and downcasts - -"Declaring data reference variables -DATA ref1 TYPE REF TO i. -DATA ref2 TYPE REF TO i. - -ref1 = NEW #( 789 ). - -"Assignments -ref2 = ref1. - -"Casting - -"Complete type -DATA(ref3) = NEW i( 321 ). - -"Generic type -DATA ref4 TYPE REF TO data. - -"Upcast -ref4 = ref3. - -"Downcasts -DATA ref5 TYPE REF TO i. - -"Generic type -DATA ref6 TYPE REF TO data. - -ref6 = NEW i( 654 ). -ref5 = CAST #( ref6 ). - -"Casting operator in older syntax -"ref5 ?= ref6. - -"Note: The cast operators can also but need not be specified for upcasts. -ref4 = CAST #( ref3 ). -``` - -**Addressing data references** - -Before addressing the content of data objects a data reference points to, you must dereference data reference variables. Use the -[dereferencing operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendereferencing_operat_glosry.htm "Glossary Entry") -`->*`. To check if dereferencing works, you can use a logical expression with [`IS BOUND`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenlogexp_bound.htm). - -``` abap -"Creating data reference variables and assign values - -DATA(ref_i) = NEW i( 1 ). -DATA(ref_carr) = NEW zdemo_abap_carr( carrid = 'LH' carrname = 'Lufthansa' ). - -"Generic type - -DATA ref_gen TYPE REF TO data. -ref_gen = ref_i. "Copying reference - -"Accessing - -"Variable number receives the content. -DATA(number) = ref_i->*. - -"Content of referenced data object is changed. -ref_i->* = 10. - -"Data reference used in a logical expression. -IF ref_i->* > 5. - ... -ENDIF. - -"Dereferenced generic type -DATA(calc) = 1 + ref_gen->*. - -"Structure -"Complete structure -DATA(struc) = ref_carr->*. - -"When dereferencing a data reference variable that has a structured -"data type, you can use the component selector -> to address individual components -DATA(carrid) = ref_carr->carrid. -ref_carr->carrid = 'UA'. - -"This longer syntax with the dereferencing operator also works. -ref_carr->*-carrname = 'United Airlines'. - -"Checking if a data reference variable can be dereferenced. -IF ref_carr IS BOUND. -  ... -ENDIF. - -DATA(ref_bound) = COND #( WHEN ref_carr IS BOUND THEN ref_carr->carrid ELSE `is not bound` ). - -"Explicitly removing a reference -"However, the garbage collector takes care of removing the references -"automatically once the data is not used any more by a reference. -CLEAR ref_carr. -``` - -**Excursion: Generic data references and field symbols** - -```abap -"Non-generic type -DATA ref_int TYPE REF TO i. -ref_int = NEW #( ). -ref_int->* = 123. - -"Generic type -DATA ref_generic TYPE REF TO data. -ref_generic = NEW i( ). "Syntax in modern ABAP -CREATE DATA ref_generic TYPE i. "Syntax for older ABAP releases - -"As mentioned above, the content of anonymous data objects can only be -"accessed using dereferenced data variables and field symbols. -"The only option to access the variable in older releases was via field symbols. -ASSIGN ref_generic->* TO FIELD-SYMBOL(). - = 123. - -"An access as the following, as it is possible in modern ABAP, was not possible. -ref_generic->* = 123. - -"In modern ABAP, variables and field symbols of the generic types -"'any' and 'data' can be used directly, for example, in LOOP and READ statements. -DATA dref TYPE REF TO data. -CREATE DATA dref TYPE TABLE OF zdemo_abap_carr. -SELECT * - FROM zdemo_abap_carr - INTO TABLE @dref->*. - -"Note: In case of a fully generic type, an explicit or implicit index operation -"is not possible (indicated by the examples commented out). -LOOP AT dref->* ASSIGNING FIELD-SYMBOL(). - ... -ENDLOOP. -"LOOP AT dref->* ASSIGNING FIELD-SYMBOL() FROM 1 TO 4. -"ENDLOOP. - -"The following examples use a dynamic key specification. -"See more syntax examples below. -READ TABLE dref->* ASSIGNING FIELD-SYMBOL() WITH KEY ('CARRID') = 'AA'. -"READ TABLE dref->* INDEX 1 ASSIGNING FIELD-SYMBOL(). - -"Table expressions -DATA(line) = CONV zdemo_abap_carr( dref->*[ ('CARRID') = 'AA' ] ). -dref->*[ ('CARRID') = 'AA' ] = VALUE zdemo_abap_carr( BASE dref->*[ ('CARRID') = 'AA' ] carrid = 'XY' ). -dref->*[ ('CARRID') = 'XY' ]-('CARRID') = 'ZZ'. - -"Table functions -DATA(num_tab_lines) = lines( dref->* ). -DATA(idx) = line_index( dref->*[ ('CARRID') = 'LH' ] ). -``` - -**Examples using data references** - -Some example contexts of using data references are as follows: - -*Overwriting data reference variables*: -``` abap -dref = NEW i( 1 ). - -"ref is overwritten here because a new object is created -"with a data reference variable already pointing to a data object -dref = NEW i( 2 ). -``` - -*Retaining data references*: - -``` abap -"This snippet shows that three data references are created -"with the same reference variable. Storing them in an internal table -"using the type TYPE TABLE OF REF TO prevents the overwriting. - -DATA: dref TYPE REF TO data, - itab TYPE TABLE OF REF TO data, - num TYPE i VALUE 0. - -DO 3 TIMES. - "Adding up 1 to demonstrate a changed data object. - num += 1. - - "Creating data reference and assigning value. - "In the course of the loop, the variable gets overwritten. - dref = NEW i( num ). - - "Adding the reference to itab - itab = VALUE #( BASE itab ( dref ) ). -ENDDO. -``` - -*Processing internal tables*: - -``` abap -"Similar use case to using field symbols: In a loop across an internal table, -"you assign the content of the line in a data reference variable -"instead of actually copying the content to boost performance. -"Again, the inline declaration comes in handy. - -"Filling an internal table. -SELECT * - FROM zdemo_abap_fli - INTO TABLE @DATA(fli_tab). - -LOOP AT fli_tab REFERENCE INTO DATA(ref). - - "A component of the table line may be addressed. - "Note the object component selector; the dereferencing operator together - "with the component selector is also possible: ->*- - ref->carrid = ... - ... -ENDLOOP. - -"More statements are available that assign content to a data reference variable, -"for example, READ TABLE. -READ TABLE fli_tab INDEX 1 REFERENCE INTO DATA(rt_ref). -``` - -*Data reference variables as part of structures and internal tables*: -``` abap -"Unlike field symbols, data reference variables can be used as -"components of structures or columns in internal tables. - -"Structure -DATA: BEGIN OF struc, - num TYPE i, - ref TYPE REF TO i, - END OF struc. - -"Some value assignment - -struc = VALUE #( num = 1 ref = NEW #( 2 ) ). - -"Internal table - -DATA itab LIKE TABLE OF struc WITH EMPTY KEY. -APPEND struc TO itab. -itab[ 1 ]-ref->* = 123. -``` - -> **✔️ Hint**
-> When to actually use either a field symbol -or a data reference variable? It depends on your use case. However, data -reference variables are more powerful as far as their usage options are -concerned, and they better fit into the modern (object-oriented) ABAP -world. Recommended read: [Accessing Data Objects Dynamically (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abendyn_access_data_obj_guidl.htm "Guideline"). - -

⬆️ back to top

- -## Dynamic ABAP Statements - -As already mentioned above, there are ABAP statements that support the dynamic specification of syntax elements. -In this context, you can usually use elementary, character-like data objects specified within a pair of parentheses. -For example, `SORT` statements: -``` abap -"Named, character-like data object specified within parentheses -"used by an ABAP statement -DATA(field_name) = 'CARRNAME'. -SORT itab BY (field_name). - -"Unnamed, character-like data object specified within parentheses -SORT itab BY ('CURRCODE'). -``` - -Note that dynamically specifying syntax elements has downsides, too. Consider some erroneous character-like content of such data objects. There is no syntax warning. At runtime, it can lead to runtime errors. -Some of the following code snippets use artifacts from the cheat sheet repository. The code snippets demonstrate a selection. - -### Dynamic ASSIGN Statements - -``` abap -"Creating and populating various types/data objects to work with -TYPES: BEGIN OF st_type, - col1 TYPE i, - col2 TYPE string, - col3 TYPE string, - END OF st_type. -DATA st TYPE st_type. -DATA it TYPE TABLE OF st_type WITH EMPTY KEY. -st = VALUE #( col1 = 1 col2 = `aaa` col3 = `Z` ). -APPEND st TO it. -DATA(dref) = NEW st_type( col1 = 2 col2 = `b` col3 = `Y` ). -DATA dobj TYPE string VALUE `hallo`. -"The following examples use a field symbol with generic type -FIELD-SYMBOLS TYPE data. - -"------- Specifying the memory area dynamically ------ -"I.e. the memory area is not specified directly, but as content of a -"character-like data object in parentheses. -"Note: -"- When specified as unnamed data object, the compiler treats the -" specifications like static assignments. Do not use named data objects -" for ASSIGN statements in ABAP for Cloud Development. It is recommended -" that existing named data objects are put in a structure. Then, the syntax -" for assigning components dynamically can be used so as to avoid a syntax -" warning. -"- Most of the following examples use an unnamed data object. -"- The specification of the name is not case-sensitive. - -ASSIGN ('IT') TO . -ASSIGN ('ST') TO . - -"Field symbol declared inline -"Note: The typing is performed with the generic type data. -ASSIGN ('DOBJ') TO FIELD-SYMBOL(). - -"The statements set the sy-subrc value. -ASSIGN ('DOES_NOT_EXIST') TO . -IF sy-subrc <> 0. - ... -ENDIF. - -"The memory area can also be a dereferenced data reference -ASSIGN dref->* TO . - -"------- Assigning components dynamically ------ -"You can chain the names with the component selector (-), or, in -"case of reference variables, the object component selector (->). -ASSIGN st-('COL1') TO . -ASSIGN it[ 1 ]-('COL1') TO . -ASSIGN dref->('COL1') TO . -"The following example uses the dereferencing operator explicitly -"followed by the component selector. -ASSIGN dref->*-('COL1') TO . - -"Using a named data object for the component specification -DATA columnname TYPE string VALUE `COL1`. -ASSIGN st-(columnname) TO . - -"Fully dynamic specification -"If the compiler can fully determine the data object in ASSIGN statements -"in ABAP for Cloud Development, a warning is not issued. -ASSIGN ('ST-COL1') TO . - -"Numeric expressions are possible. Its value is interpreted -"as the position of the component in the structure. -ASSIGN st-(3) TO . - -"If the value is 0, the memory area of the entire structure is -"assigned to the field symbol. -ASSIGN st-(0) TO . - -"The statements above replace the following, older statements. -ASSIGN COMPONENT 'COL1' OF STRUCTURE st TO . -ASSIGN COMPONENT 3 OF STRUCTURE st TO . - -"------- Assigning attributes of classes or interfaces dynamically ------ -"The following syntax pattern shows the possible specifications. -"... cref->(attr_name) ... "object reference variable -"... iref->(attr_name) ... "interface reference variable -"... (clif_name)=>(attr_name) ... "class/interface name -"... (clif_name)=>attr ... -"... clif=>(attr_name) ... - -"Creating an instance of a class -DATA(oref) = NEW zcl_demo_abap_objects( ). - -"Assigning instance attributes using an object reference variable -"All visible attributes of objects can be assigned. -oref->string = `ABAP`. "Assigning a value to the attribute for demo purposes -ASSIGN oref->('STRING') TO . - -"Assigning instance attributes using an interface reference variable -DATA iref TYPE REF TO zdemo_abap_objects_interface. -iref = oref. -ASSIGN iref->('STRING') TO . -iref->in_str = `hallo`. -ASSIGN iref->('IN_STR') TO . - -"Assigning static attributes -"All visible static attributes in classes and interfaces can be assigned -"In the following example, a class and an interface are specified statically, -"and the attributes are specified dynamically. -ASSIGN zcl_demo_abap_objects=>('PUBLIC_STRING') TO . -ASSIGN zdemo_abap_objects_interface=>('CONST_INTF') TO . - -"Specifying a class or interface dynamically, and attributes statically -ASSIGN ('ZCL_DEMO_ABAP_OBJECTS')=>public_string TO . -ASSIGN ('ZDEMO_ABAP_OBJECTS_INTERFACE')=>const_intf TO . - -"Specifying a class or interface as well as attributes dynamically -ASSIGN ('ZCL_DEMO_ABAP_OBJECTS')=>('PUBLIC_STRING') TO . -ASSIGN ('ZDEMO_ABAP_OBJECTS_INTERFACE')=>('CONST_INTF') TO . - -"Further dynamic syntax options are possible, for example, -"specifying the memory area after ASSIGN with a writable expression -"because the operand position after ASSIGN is a result position. -ASSIGN NEW zcl_demo_abap_objects( )->('PUBLIC_STRING') TO . - -"ELSE UNASSIGN addition -"If ELSE UNASSIGN is specified in the context of dynamic assignments/accesses, -"no memory area is assigned to the field symbol. It is unassigned after -"the ASSIGN statement. -"Note: For the static variant of the ASSIGN statement, i.e. if the memory area -"to be assigned following the ASSIGN keyword is statically specified, the addition -"ELSE UNASSIGN is implicitly set and cannot be used explicitly. -DATA(hallo) = `Hallo world`. -ASSIGN ('HALLO') TO FIELD-SYMBOL() ELSE UNASSIGN. -ASSERT sy-subrc = 0 AND IS ASSIGNED. -ASSIGN ('DOES_NOT_EXIST') TO ELSE UNASSIGN. -ASSERT sy-subrc = 4 AND IS NOT ASSIGNED. -``` - -> **💡 Note**
-> - The following `ASSIGN` statements set the `sy-subrc` value: dynamic assignments, dynamic component assignment, dynamic invokes, assignments of table expressions. -> - The return code is not set for a static assignment and an assignment of the constructor operator `CAST`. - -

⬆️ back to top

- -### Dynamically Specifying Data Types/Creating (Data) Objects - -- For dynamic syntax elements in `CREATE OBJECT` statements, find more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object_explicit.htm) (note that parameters can be specified dynamically, too). -- In addition to character-like data objects for the type name specified in the parentheses, you can also use [absolute type names](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabsolute_typename_glosry.htm) (see the information about RTTI below). - -``` abap -"Anonymous data objects are created using a type determined at -"runtime. See more information below. Note that the NEW operator -"cannot be used here. -DATA(some_type) = 'STRING'. -DATA dataref TYPE REF TO data. -CREATE DATA dataref TYPE (some_type). -CREATE DATA dataref TYPE TABLE OF (some_type). -CREATE DATA dataref TYPE REF TO (some_type). -"Using an absolute type name -CREATE DATA dataref TYPE ('\TYPE=STRING'). - -"Assigning a data object to a field symbol casting a dynamically -"specified type -TYPES clen5 TYPE c LENGTH 5. -DATA: dobj_c10 TYPE c LENGTH 10 VALUE '1234567890', - some_struct TYPE zdemo_abap_fli. -FIELD-SYMBOLS TYPE data. - -ASSIGN dobj_c10 TO CASTING TYPE ('CLEN5'). "12345 -ASSIGN dobj_c10 TO CASTING LIKE some_struct-('CARRID'). "123 - -"Dynamically creating an object as an instance of a class and -"assigning the reference to the object to an object reference -"variable. oref can be an object or interface reference variable. -"The reference variable is created here with the generic 'object'. -DATA oref_dyn TYPE REF TO object. -CREATE OBJECT oref_dyn TYPE ('ZCL_DEMO_ABAP_OBJECTS'). -"Accessing an instance attribute -oref_dyn->('ANOTHER_STRING') = `hi`. - -"Note: As covered further down and in the executable example, -"CREATE DATA and ASSIGN statements have the HANDLE addition -"after which dynamically created types can be specified. A type -"description object is expected. - -"Getting type description object -DATA(tdo_elem) = cl_abap_elemdescr=>get_c( 4 ). -CREATE DATA dataref TYPE HANDLE tdo_elem. -dataref->* = dobj_c10. "1234 -ASSIGN dobj_c10 TO CASTING TYPE HANDLE tdo_elem. "1234 -``` - -

⬆️ back to top

- -### Accessing Structure Components Dynamically - -``` abap -"Creating and populating various types/data objects to work with -TYPES: BEGIN OF st_type, - col1 TYPE i, - col2 TYPE string, - col3 TYPE string, - END OF st_type. -DATA st TYPE st_type. -DATA it TYPE TABLE OF st_type WITH EMPTY KEY. -st = VALUE #( col1 = 1 col2 = `aaa` col3 = `Z` ). -APPEND st TO it. -DATA(dref) = NEW st_type( col1 = 2 col2 = `b` col3 = `Y` ). - -"You can achieve the access using ASSIGN statements as shown above, or -"by statically specifying the structure and the (object) component selector -"followed by a character-like data object in parentheses. -"Write position -st-('COL1') = 123. -it[ 1 ]-('COL1') = 456. -dref->('COL1') = 789. - -"Read position -"The example shows how you can retrieve the textual content of any component -"of any structure. -DATA(content_col2) = CONV string( st-('COL1') ). -DATA(content_col3) = |{ st-('COL3') }|. -DATA content_col1 LIKE st-col1. -content_col1 = st-('COL1'). - -DATA dref_comp TYPE REF TO data. -CREATE DATA dref_comp LIKE st-('COL3'). -dref_comp->* = st-('COL3'). - -"If the component is not found, a catchable exception is raised. -TRY. - DATA(col_not_existent) = |{ st-('COL123') }|. - CATCH cx_sy_assign_illegal_component. - ... -ENDTRY. - -"Accessing components of generic structures dynamically, -"e.g. if you have a method parameter that is typed with the generic type -"data. -"The example uses a field symbol with the generic type data which is assigned -"a structure. -FIELD-SYMBOLS TYPE data. -ASSIGN st TO . - -"As in the examples above, specifying components dynamically is possible. --('COL2') = `ABAP`. -DATA(gen_comp) = CONV string( -('COL2') ). - -"Excursion -"In the following example, a structure is assigned to a field symbol that -"has a generic type. The components of the structure are accessed dynamically in -"a DO loop. The sy-index value is interpreted as the position of the component -"in the structure. Plus, using RTTI - as also shown further down - the component -"names are retrieved. Component names and the values are added to a string. As a -"prerequisite, all component values must be convertible to type string. -DATA struc2string TYPE string. -FIELD-SYMBOLS TYPE data. -ASSIGN st TO . -IF sy-subrc = 0. - TRY. - DATA(comps) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( ) )->components. - DO. - TRY. - DATA(comp_name) = comps[ sy-index ]-name. - struc2string = struc2string && - COND #( WHEN sy-index <> 1 THEN `, ` ) && - comp_name && `: "` && - -(sy-index) && `"`. - CATCH cx_sy_assign_illegal_component cx_sy_itab_line_not_found. - EXIT. - ENDTRY. - ENDDO. - CATCH cx_sy_move_cast_error. - ENDTRY. -ENDIF. -"struc2string: COL1: "123", COL2: "ABAP", COL3: "Z" -``` - -

⬆️ back to top

- -### Dynamic Specifications in Statements for Processing Internal Tables - -```abap -"Creating and populating various types/data objects to work with -TYPES: BEGIN OF demo_struct, - col1 TYPE i, - col2 TYPE string, - col3 TYPE string, - END OF demo_struct. -DATA itab_ek TYPE TABLE OF demo_struct WITH EMPTY KEY. -"Standard table and specification of primary and secondary table key -DATA itab TYPE TABLE OF demo_struct - WITH NON-UNIQUE KEY col1 - WITH UNIQUE SORTED KEY sk COMPONENTS col2. -TYPES itab_type LIKE itab. -DATA itab_ref TYPE TABLE OF REF TO demo_struct WITH EMPTY KEY. -itab_ek = VALUE #( ( col1 = 1 col2 = `aaa` col3 = `zzz` ) - ( col1 = 2 col2 = `bbb` col3 = `yyy` ) - ( col1 = 3 col2 = `ccc` col3 = `xxx` ) ). -itab = itab_ek. -itab_ref = VALUE #( ( NEW demo_struct( col1 = 1 col2 = `aaa` col3 = `zzz` ) ) ). - -"Notes -"- In statements using key specifications, secondary table key names (or alias names) -" are usually specified. Also the primary table key using the predefined name -" primary_key or its alias name can be used. -"- Many of the following statements provide similar additions offering dynamic -" specifications, such as USING KEY and dynamic component name specifications. - -"------- SORT ------ -"Named data object specified within parenteses -DATA(field_name) = 'COL1'. -SORT itab_ek BY (field_name) DESCENDING. -"Unnamed data object specified within parenteses -SORT itab_ek BY ('COL2') ASCENDING. - -"------- READ TABLE ------ -"Reading by specifying keys dynamically -"Implicitly specifying the table key values in a work area (USING KEY addition) -DATA(wa_read) = VALUE demo_struct( col2 = `aaa` ). -READ TABLE itab FROM wa_read USING KEY ('SK') REFERENCE INTO DATA(read_ref). - -"Explicitly specifying the key and key values (TABLE KEY addition) -"The component names can also be specified dynamically (which is done in most of the -"following examples for demonstration purposes). Note that each component of the table -"key must be specified. -READ TABLE itab WITH TABLE KEY ('SK') COMPONENTS ('COL2') = `aaa` REFERENCE INTO read_ref. -"Specifying the predefined name primary_key explicitly and dynamically -READ TABLE itab WITH TABLE KEY ('PRIMARY_KEY') COMPONENTS ('COL1') = 1 REFERENCE INTO read_ref. -"If the addition COMPONENTS is not specified, the primary table key is implicitly used. -READ TABLE itab WITH TABLE KEY ('COL1') = 1 REFERENCE INTO read_ref. - -"Reading using a free key (WITH KEY addition) -READ TABLE itab WITH KEY ('COL3') = `yyy` REFERENCE INTO read_ref. -"The addition can also be used by specifying a secondary table key name -READ TABLE itab WITH KEY ('SK') COMPONENTS ('COL2') = `ccc` REFERENCE INTO read_ref. - -"Reading based on a table index (INDEX addition) -"Not using the addition USING KEY means reading from the primary table index. -READ TABLE itab INDEX 1 USING KEY ('SK') REFERENCE INTO read_ref. - -"More dynamic specification options when specifying the target as work area -"(COMPARING/TRANSPORTING additions) -"TRANSPORTING: Specifying which components shall be respected -READ TABLE itab INDEX 1 INTO DATA(workarea) TRANSPORTING ('COL1') ('COL3'). - -"COMPARING: If the content of the compared components is identical, sy-subrc is set -"to 0, and otherwise to 2. The line found is assigned to the work area independently -"of the result of the comparison. -workarea-('COL3') = `uvw`. -READ TABLE itab INDEX 1 INTO workarea COMPARING ('COL3') TRANSPORTING ('COL1') ('COL3'). -IF sy-subrc <> 0. - ... -ENDIF. - -"------- Table expressions ------ -"Similar to READ TABLE statements, you can specify table lines with 3 alternatives: -"index read, read using free key, table key -"Also there, dynamic specifications are possible regarding the key specifications. - -"Reading based on index with dynamic key specifications -"Specifying the secondary table index of a sorted secondary key -DATA(wa_te1) = itab[ KEY ('SK') INDEX 1 ]. -"Reading using a free key, the keys are specified dynamically -DATA(wa_te2) = itab[ ('COL2') = `bbb` ('COL3') = `yyy` ]. - -"Reading using a table key -"Specyfing the table key explicitly -"Note: Unlike READ TABLE statements, the name of the table key must be specified. The -"addition COMPONENTS can be omitted. -"In the following example, the component names are also specified dynamically. -DATA(wa_te3) = itab[ KEY ('SK') ('COL2') = `ccc` ]. -"Specifying the COMPONENTS addition explicitly -DATA(wa_te4) = itab[ KEY ('PRIMARY_KEY') COMPONENTS ('COL1') = 1 ]. - -"Accessing components -"As shown above, chaininings with the (object) component selector are possible. -"The examples use index access and write positions. -itab[ 1 ]-('COL2') = `jkl`. -itab_ref[ 1 ]->('COL2') = `mno`. - -"------- LOOP AT ------ -"USING KEY addition: Overriding the standard order determined by the table category -LOOP AT itab REFERENCE INTO DATA(ref) USING KEY ('SK'). - ... -ENDLOOP. - -"When the primary table key is specified, the loop behaves as if it was not specified. -"So, the following statement corresponds to the one below. -LOOP AT itab REFERENCE INTO ref USING KEY ('PRIMARY_KEY'). - ... -ENDLOOP. - -LOOP AT itab REFERENCE INTO ref. - ... -ENDLOOP. - -"Dynamic WHERE condition -"You can specify a character-like data object or a standard table with character-like -"line type. -DATA(cond_loop) = `COL1 > 1`. -LOOP AT itab REFERENCE INTO ref WHERE (cond_loop). - ... -ENDLOOP. - -"------- INSERT ------ -"The USING KEY addition (which accepts a dynamic specification) affects the order in which lines are inserted. - -"Result of the following example when using the ... -"- secondary table key: order of itab entries 5 ... /4 ... /... -"- primary table key: order of itab entries 4 ... /5 ... /... -INSERT LINES OF VALUE itab_type( ( col1 = 4 col2 = `eee` col3 = `www` ) - ( col1 = 5 col2 = `ddd` col3 = `vvv` ) ) - USING KEY ('SK') - "USING KEY ('PRIMARY_KEY') - INTO itab INDEX 1. - -"Excursion: Using LOOP AT statements with the USING KEY addition -"and exploring the table index -"Declaring demo tables to hold the internal table entries -DATA it_seckey_idx TYPE TABLE OF demo_struct WITH EMPTY KEY. -DATA it_primekey_idx LIKE it_seckey_idx. - -"Visualizing the secondary table index -LOOP AT itab INTO DATA(wa_sk) USING KEY ('SK'). - APPEND wa_sk TO it_seckey_idx. -ENDLOOP. - -"Visualizing the primary table index -LOOP AT itab INTO DATA(wa_pk) USING KEY ('PRIMARY_KEY'). - APPEND wa_pk TO it_primekey_idx. -ENDLOOP. - -"------- MODIFY ------ -"In the following example, a line is modified based on a work area and a table key. -"The component col1 is left out from the work area intentionally. -"If the primary table key was used, the value of sy-subrc would be 4, and no modification was done. -"The optional addition transporting is specified to denote what should be modified. In this example, -"the component is also specified dynamically. -MODIFY TABLE itab FROM VALUE #( col2 = `bbb` col3 = `uuu` ) USING KEY ('SK') TRANSPORTING ('COL3'). - -"In the following example, a line is modified based on a work area, an index specification and a -"table key. -"INDEX can also be positioned after FROM. -MODIFY itab INDEX 2 USING KEY ('SK') FROM VALUE #( col3 = `ttt` ) TRANSPORTING ('COL3'). - -"Dynamic WHERE clause (only to be used with the TRANSPORTING addition) -"The USING KEY addition is also possible. Check the ABAP Keyword Documentation -"for special rules that apply. -DATA(cond_mod) = `COL1 < 3`. -MODIFY itab FROM VALUE #( col3 = `sss` ) TRANSPORTING ('COL3') WHERE (cond_mod). - -"------- DELETE ------ -"A single line or multipled lines can be deleted. -"Note that DELETE ADJACENT DUPLICATES statements can also be specified using -"dynamic parts. - -"Deleting based on a dynamically specified table key -"The values can be declared either implicitly in a work area after FROM or explicitly -"by listing the components of the table key after TABLE KEY. -"If the USING KEY addition is not specified, the primary table key is used by default. -DELETE TABLE itab FROM VALUE #( col2 = `eee` col3 = `www` ) USING KEY ('SK'). - -"Each component of the table key must be listed. -DELETE TABLE itab WITH TABLE KEY ('SK') COMPONENTS ('COL2') = `ddd`. - -"Deleting based on the table index -DELETE itab INDEX 1 USING KEY ('SK'). - -"Deleting multiple lines and specifying the WHERE conditions dynamically -"The USING KEY addition is also possible. -DATA(condition_tab) = VALUE string_table( ( `COL1 < 3` ) - ( `OR` ) - ( `COL3 = ``www``` ) ). -DELETE itab WHERE (condition_tab). -``` - -

⬆️ back to top

- -### Dynamic ABAP SQL Statements - -```abap -"Dynamic SELECT list -DATA(select_list) = `CARRID, CONNID, FLDATE`. -DATA fli_tab TYPE TABLE OF zdemo_abap_fli WITH EMPTY KEY. - -SELECT (select_list) - FROM zdemo_abap_fli - INTO CORRESPONDING FIELDS OF TABLE @fli_tab. - -"Dynamic FROM clause -DATA(table) = 'ZDEMO_ABAP_FLI'. -SELECT * - FROM (table) - INTO TABLE @fli_tab. - -"Excursion: Compatible target data objects -"In the examples above, the data object/type is created statically. - -"Creating an anonymous data object with a CREATE DATA statement -"and specifiying the type dynamically. -"You can use the dereferenced object reference variable as target. -DATA itab_dyn TYPE REF TO data. -CREATE DATA itab_dyn TYPE TABLE OF (table). - -SELECT * - FROM (table) - INTO TABLE @itab_dyn->*. - -"In older ABAP code, you may find assignments to a field symbol -"due to the reasons mentioned above. -FIELD-SYMBOLS TYPE ANY TABLE. -ASSIGN itab_dyn->* TO . - -SELECT * - FROM (table) - INTO TABLE @. - -"Similar to the NEW operator, you can use the addition NEW -"to create an anonymous data object in place. The advantage is -"that the data type is constructed in a suitable way. -SELECT * - FROM (table) - INTO TABLE NEW @DATA(dref_tab). - -"Dynamic WHERE clause -"The example includes a WHERE clause that is created as an internal -"table with a character-like row type. -DATA(where_clause) = VALUE string_table( ( `CARRID = 'LH'` ) - ( `OR` ) - ( `CARRID = 'AA'` ) ). - -SELECT * - FROM zdemo_abap_fli - WHERE (where_clause) - INTO TABLE NEW @DATA(tab_dyn_where). - -"Dynamic ORDER BY clause -SELECT * - FROM zdemo_abap_fli - ORDER BY (`FLDATE`) - INTO TABLE NEW @DATA(tab_dyn_order). - -"SELECT statement with miscellaneous dynamic specifications -SELECT (`CARRID, CONNID, FLDATE`) - FROM (`ZDEMO_ABAP_FLI`) - WHERE (`CARRID <> ``AA```) - ORDER BY (`FLDATE`) - INTO TABLE NEW @DATA(tab_dyn_misc). - -"Further dynamic specifications in other ABAP SQL statements -"Creating a structure to be inserted into the database table -SELECT SINGLE * - FROM (table) - INTO NEW @DATA(dref_struc). -dref_struc->('CARRID') = 'YZ'. - -INSERT (table) FROM @dref_struc->*. - -dref_struc->('CURRENCY') = 'EUR'. -UPDATE (table) FROM @dref_struc->*. - -dref_struc->('SEATSOCC') = 10. -MODIFY (table) FROM @dref_struc->*. - -DELETE FROM (table) WHERE (`CARRID = 'YZ'`). -``` - -

⬆️ back to top

- -**Excursion**: To take up the use case mentioned in the introduction about retrieving the content of a database table, storing it in an internal table, and -displaying it when the database table name is specified dynamically at -runtime, see the following code snippet. Note the comments. - - -```abap -CLASS zcl_example_class DEFINITION - PUBLIC - FINAL - CREATE PUBLIC . - - PUBLIC SECTION. - INTERFACES if_oo_adt_classrun. - PROTECTED SECTION. - PRIVATE SECTION. -ENDCLASS. -CLASS zcl_example_class IMPLEMENTATION. - METHOD if_oo_adt_classrun~main. - "The example retrieves the content of a database table, storing it in an - "internal table, and displaying it when the database table name is - "specified dynamically at runtime. - "Certainly, there are quite some ways to achieve it, and that work out - "of the box. For example, in ABAP for Cloud Development, you can implement - "the classrun if_oo_adt_classrun and output content using the out->write(...) - "method. You can also inherit from cl_demo_classrun in your class. In - "classic ABAP, you can, for example and additionally, use cl_demo_output or - "ALV. - "Notes: - "- The following example is just ABAP code exploring dynamic programming - " aspects. Note the disclaimer in the README of the cheat sheet repository. - " It is an example that sets its focus on a dynamic SELECT statement and - " processing internal table content by dynamically accessing structure - " components. - "- The ways mentioned above are way more powerful (e.g. in most cases also - " nested and deep data objects can be displayed for demo purposes). - "- For simplicity, column contents are converted to string here if necessary, - " i.e. all column contents must be convertible to string. - "- For display purposes, the snippet uses the classrun methods to display - " results sequentially - instead of displaying the internal table - " content retrieved by the SELECT statement directly. - "- The example uses database tables from the cheat sheet repository. To fill - " them, you can use the method call zcl_demo_abap_aux=>fill_dbtabs( ).. - zcl_demo_abap_aux=>fill_dbtabs( ). - - "Data objects and types relevant for the example (length and offset for - "content display) - DATA str TYPE string. - TYPES: BEGIN OF comp_struc, - name TYPE string, - len TYPE i, - off TYPE i, - END OF comp_struc. - DATA it_comps TYPE TABLE OF comp_struc WITH EMPTY KEY. - - "Database table of type string containing names of database tables; - "table is looped over to output content of all database tables - DATA(dbtabs) = VALUE string_table( ( `ZDEMO_ABAP_CARR` ) - ( `ZDEMO_ABAP_FLI` ) - ( `ZDEMO_ABAP_FLSCH` ) ). - - LOOP AT dbtabs INTO DATA(dbtab). - "Retrieving database content of a dynamically specified database table - TRY. - SELECT * - FROM (dbtab) - INTO TABLE NEW @DATA(itab) - UP TO 5 ROWS. - CATCH cx_sy_dynamic_osql_semantics INTO DATA(sql_error). - CLEAR itab->*. - out->write( |Table { dbtab } does not exist.| ). - ENDTRY. - - IF sql_error IS INITIAL. - "Getting table component names using RTTI methods - TRY. - DATA(type_descr_obj_tab) = CAST cl_abap_tabledescr( - cl_abap_typedescr=>describe_by_data( itab->* ) ). - DATA(tab_comps) = CAST cl_abap_structdescr( - type_descr_obj_tab->get_table_line_type( ) )->get_components( ). - LOOP AT tab_comps ASSIGNING FIELD-SYMBOL(). - APPEND VALUE #( name = -name len = strlen( -name ) ) TO it_comps. - ENDLOOP. - CATCH cx_sy_move_cast_error INTO DATA(error). - out->write( |{ error->get_text( ) }| ). - ENDTRY. - - IF error IS INITIAL. - out->write( |\n| ). - out->write( |Retrieved content of database table { dbtab }:| ). - "Implementation for properly aligning the content - "The example is implemented to check the length of the column names as well as the - "length of the values in the columns. It determines the length of the longest string - "in each column. Depending on the length values, either the length of the column name - "or the length of the longest string in a column is stored in an internal table that - "contains information for calculating the offset. - LOOP AT tab_comps ASSIGNING FIELD-SYMBOL(). - ASSIGN it_comps[ name = -name ] TO FIELD-SYMBOL(). - DATA(max_content) = REDUCE i( INIT len = -len - FOR IN itab->* - NEXT len = COND #( WHEN strlen( CONV string( -(-name) ) ) > len - THEN strlen( CONV string( -(-name) ) ) - ELSE len ) ). - "Extend the length value to leave some more space - IF max_content > -len. - -len = max_content + 3. - ELSE. - -len += 3. - ENDIF. - ENDLOOP. - "Calculating offset values - DATA max_str_len TYPE i. - LOOP AT it_comps ASSIGNING FIELD-SYMBOL(). - DATA(tabix) = sy-tabix. - READ TABLE it_comps INDEX tabix - 1 ASSIGNING FIELD-SYMBOL(). - -off = COND #( WHEN tabix = 1 THEN 0 ELSE -len + -off ). - max_str_len += -len. - ENDLOOP. - "Providing enough space so that table row content can be inserted based on - "the offset specification - SHIFT str BY max_str_len PLACES RIGHT. - "Adding the column names first - LOOP AT it_comps ASSIGNING FIELD-SYMBOL(
). - str = insert( val = str sub =
-name off =
-off ). - ENDLOOP. - out->write( str ). - "Processing all lines in the internal table containing the retrieved table rows - LOOP AT itab->* ASSIGNING FIELD-SYMBOL(). - CLEAR str. - SHIFT str BY max_str_len PLACES RIGHT. - DO. - TRY. - str = insert( val = str sub = -(sy-index) off = it_comps[ sy-index ]-off ). - CATCH cx_sy_assign_illegal_component cx_sy_range_out_of_bounds cx_sy_itab_line_not_found. - EXIT. - ENDTRY. - ENDDO. - out->write( str ). - ENDLOOP. - ENDIF. - out->write( |\n| ). - CLEAR: str, it_comps. - ENDIF. - ENDLOOP. - ENDMETHOD. -ENDCLASS. -``` - -

⬆️ back to top

- -### Dynamic Invoke -The following code snippet shows dynamically specifying [procedure](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") calls. - -``` abap -"Note: Dynamic method calls require a CALL METHOD statement. -"The following examples assume that there are no mandatory -"parameters defined for the method. -"Possible for methods of the same class, works like me->(meth) -CALL METHOD (meth). -"Class specified statically -CALL METHOD class=>(meth). -"Object reference variable specified statically; -"also possible for interface reference variables -CALL METHOD oref->(meth). - -"The following statements are possible for all visible static methods -"Class dynamically specified -CALL METHOD (class)=>meth. -"Class and method dynamically specified -CALL METHOD (class)=>(meth). - -"The following examples assume that there are parameters defined -"for the method. -"Assigning actual parameters to the formal parameters statically -CALL METHOD class=>(meth) EXPORTING p1 = a1 p2 = a2 ... - IMPORTING p1 = a1 p2 = a2 ... - -"Assigning actual parameters to the formal parameters dynamically -DATA ptab TYPE abap_parmbind_tab. -ptab = ... - -CALL METHOD class=>(meth) PARAMETER-TABLE ptab. - -"Notes on PARAMETER-TABLE ptab -"- The table (of type abap_parmbind_tab; line type is abap_parmbind) -" must be filled and have a line for all non-optional parameters. -"- Components: name -> formal parameter name -" kind -> kind of parameter, e. g. importing -" value -> pointer to appropriate actual parameter, -" is of type REF TO data -"The addition EXCEPTION-TABLE for exceptions is not dealt with here. - -"Example that uses the PARAMETER-TABLE addition -"Creating an instance by specifying the type statically -"An example class of the cheat sheet repository is used. -DATA(oref1) = NEW zcl_demo_abap_objects( ). -"Calling an instance method -"The method multiplies an integer by 3. -"The calculation result is returned. -DATA(result) = oref1->triple( i_op = 2 ). "6 - -"Dynamic equivalent -"Creating an instance of a class by specifying the type -"dynamically -DATA oref2 TYPE REF TO object. -CREATE OBJECT oref2 TYPE ('ZCL_DEMO_ABAP_OBJECTS'). - -"Creating parameter table -DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'I_OP' - kind = cl_abap_objectdescr=>exporting - value = NEW i( 3 ) ) - ( name = 'R_TRIPLE' - kind = cl_abap_objectdescr=>returning - value = NEW i( ) ) ). - -"Dynamic method call and specifying a parameter table -CALL METHOD oref2->('TRIPLE') PARAMETER-TABLE ptab. -result = ptab[ name = 'R_TRIPLE' ]-('VALUE')->*. "9 -``` - -

⬆️ back to top

- -### Validating Input for Dynamic Specifications (CL_ABAP_DYN_PRG) - -You can use the `CL_ABAP_DYN_PRG` class to validate input for dynamic specifications. -There are several methods for different use cases. See the class documentation (click F2 on the class name in ADT) for more information. -The following examples show some of those methods. If the validation is successful, the methods in the examples return the input value. -Otherwise, an exception is raised. - -```abap -"The following method checks database table names. The name is provided -"with the val parameter. The packages formal parameter expects a table -"containing the names of packages in which the specified table should be -"included. Assuming you provide incorrect input for the table name, or -"the table is not contained in the specified packages, you can expect an -"exception to be raied. - -TRY. - DATA(dbtab) = cl_abap_dyn_prg=>check_table_name_tab( - val = `ZDEMO_ABAP_FLI` - packages = VALUE #( ( `TEST_ABAP_CHEAT_SHEETS` ) - ( `TEST_SOME_PACK` ) ) ). - - SELECT SINGLE * FROM (dbtab) INTO NEW @DATA(ref_wa). - CATCH cx_abap_not_a_table cx_abap_not_in_package. - ... -ENDTRY. - -"In the following examples, a method is used to check whether -"the input is allowed or not. For this, you specify an allowlist. -"Here, the relvant parameter expects a comma-separated list of -"allowed values. -TRY. - DATA(value1) = cl_abap_dyn_prg=>check_allowlist( - val = `A` - allowlist_str = `A,B,C,D` ). - - ... "Here might go an ABAP SQL statement with a dynamic specification. - CATCH cx_abap_not_in_allowlist. - ... -ENDTRY. - -"Another parameter of the method expects an internal table that -"contains the allowed values. -TRY. - DATA(value2) = cl_abap_dyn_prg=>check_allowlist( - val = `XYZ` - allowlist_htab = VALUE #( ( `A` ) - ( `B` ) - ( `C` ) - ( `D` ) ) ). - - ... "Here might go an ABAP SQL statement with a dynamic specification. - CATCH cx_abap_not_in_allowlist. - ... -ENDTRY. -``` - -

⬆️ back to top

- -## Runtime Type Services (RTTS) - -[RTTS](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_services_glosry.htm "Glossary Entry") -represent a hierarchy of [type description classes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentype_class_glosry.htm "Glossary Entry") -containing methods for -- getting type information on data objects, data types or - [instances](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninstance_glosry.htm "Glossary Entry") - at runtime ([Runtime Type Identification (RTTI)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm "Glossary Entry")). -- defining and creating new data types as [type description objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentype_object_glosry.htm) at runtime ([Runtime Type Creation (RTTC)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_creation_glosry.htm "Glossary Entry")). - -The hierarchy of type description classes is as follows. - -
-CL_ABAP_TYPEDESCR
-  |
-  |--CL_ABAP_DATADESCR
-  |   |
-  |   |--CL_ABAP_ELEMDESCR
-  |   |   |
-  |   |   |--CL_ABAP_ENUMDESCR
-  |   |
-  |   |--CL_ABAP_REFDESCR
-  |   |--CL_ABAP_COMPLEXDESCR
-  |       |
-  |       |--CL_ABAP_STRUCTDESCR
-  |       |--CL_ABAP_TABLEDESCR
-  |
-  |--CL_ABAP_OBJECTDESCR
-     |
-     |--CL_ABAP_CLASSDESCR
-     |--CL_ABAP_INTFDESCR
-
-So, the -[superclass](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensuperclass_glosry.htm "Glossary Entry") -`CL_ABAP_TYPEDESCR` has multiple -[subclasses](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensubclass_glosry.htm "Glossary Entry"), -for example, to deal with each kind of type. -Working with this inheritance tree means making use of -[casts](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abencast_glosry.htm "Glossary Entry"), -especially -[downcasts](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendown_cast_glosry.htm "Glossary Entry") when retrieving information at runtime. -Detailing out all the possibilities for the information retrieval and -type creation is beyond scope. Check the information, options and -various methods that can be used in the class documentation, e. g. using -F2 help information in -[ADT](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenadt_glosry.htm "Glossary Entry"), -for more details. - -

⬆️ back to top

- -### Getting Type Information at Runtime - -With RTTI, you can determine data types at runtime using description methods in type description classes. -To get the type information, you can get a reference to a type description object of a type, that is, an instance of a type description class. -The type properties are represented by attributes that are accessible through the type description object. - - -> **💡 Note**
-> - For each type, there is exactly one type description object. -> - For each type category (elementary type, table, and so on), there is a type description class (e.g. `CL_ABAP_STRUCTDESCR` for structures, as shown in the hierarchy tree above) that has special attributes (i.e. the properties of the respective types). -> - References to type description objects can be used, for example, after the `TYPE HANDLE` addition of the `CREATE DATA` and `ASSIGN` statements. - -The following examples show the retrieval of type information. Instead of the extra declaration of data reference variables, you can use -[inline declarations](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninline_declaration_glosry.htm "Glossary Entry"). -[Method chaining](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenmethod_chaining_glosry.htm "Glossary Entry") -comes in handy, too. - -```abap -"------------------------------------------------------------------------ -"---------------- Getting general type information ---------------------- -"------------------------------------------------------------------------ - -"Getting references to type description objects of a type ... - -"... using the cl_abap_typedescr=>describe_by_name method. -"In this case, the name of the types are used. -"The following examples cover elementary, structured and -"internal table types. -TYPES elemtype TYPE n LENGTH 3. -TYPES structype TYPE zdemo_abap_carr. -TYPES strtabtype TYPE string_table. - -"The reference in the type description object references an -"object from one of the classes CL_ABAP_ELEMDESCR, CL_ABAP_ENUMDESCR, -"CL_ABAP_REFDESCR, CL_ABAP_STRUCTDESCR, CL_ABAP_TABLEDESCR, -"CL_ABAP_CLASSDESCR, or CL_ABAP_INTFDESCR. You may want to check the -"content of the type description objects in the debugger. -DATA(tdo_by_name_elem) = cl_abap_typedescr=>describe_by_name( 'ELEMTYPE' ). -DATA(tdo_by_name_struc) = cl_abap_typedescr=>describe_by_name( 'STRUCTYPE' ). -DATA(tdo_by_name_itab) = cl_abap_typedescr=>describe_by_name( 'STRTABTYPE' ). - -"Inline declarations are handy to avoid helper variables such as -"in the following example. -DATA tdo_by_name_elem_helper TYPE REF TO cl_abap_typedescr. -tdo_by_name_elem_helper = cl_abap_typedescr=>describe_by_name( 'ELEMTYPE' ). - -"... using the cl_abap_typedescr=>describe_by_data method. -"In this case, the data objects are provided. -"The examples cover an elementary data object, a structure and and -"internal table. -DATA elemdobj TYPE elemtype. -DATA strucdobj TYPE structype. -DATA tabledobj TYPE strtabtype. - -DATA(tdo_by_data_elem) = cl_abap_typedescr=>describe_by_data( 'ELEMTYPE' ). -DATA(tdo_by_data_struc) = cl_abap_typedescr=>describe_by_data( 'STRUCTYPE' ). -DATA(tdo_by_data_itab) = cl_abap_typedescr=>describe_by_data( 'STRTABTYPE' ). - -"... using the cl_abap_typedescr=>describe_by_data_ref method -"In this case, a data reference variable is used. -"Note: As a result, the method returns a reference that points to -"an object in one of the classes CL_ABAP_ELEMDESCR, CL_ABAP_ENUMDESCR, -"CL_ABAP_REFDESCR, CL_ABAP_STRUCTDESCR, or CL_ABAP_TABLEDSECR. - -DATA dref1 TYPE REF TO i. -dref1 = NEW #( ). -"Data reference pointing to CL_ABAP_ELEMDESCR -DATA(tdo_by_dref1) = cl_abap_typedescr=>describe_by_data_ref( dref1 ). -"Data reference pointing to CL_ABAP_TABLEDSECR -DATA(dref2) = NEW string_table( ). -DATA(tdo_by_dref2) = cl_abap_typedescr=>describe_by_data_ref( dref2 ). - -"... using the cl_abap_typedescr=>describe_by_data_ref method -"In this case, an object reference variable is used. -DATA oref TYPE REF TO zcl_demo_abap_objects. -oref = NEW #( ). -DATA(tdo_by_oref) = cl_abap_typedescr=>describe_by_object_ref( oref ). - -"------------------------------------------------------------------------ -"--- Getting more detailed information by programmatically accessing ---- -"--- the attributes ----------------------------------------------------- -"------------------------------------------------------------------------ - -"------------------------------------------------------------------------ -"--- Examples using a type description object for an elementary type ---- -"------------------------------------------------------------------------ -DATA(elem_kind) = tdo_by_name_elem->kind. "E (elementary) -DATA(elem_absolute_name) = tdo_by_name_elem->absolute_name. "Check in the debugger for such a local type -DATA(elem_relative_name) = tdo_by_name_elem->get_relative_name( ). "ELEMTYPE -DATA(elem_is_ddic_type) = tdo_by_name_elem->is_ddic_type( ). "has the value abap_false - -"Getting more information using type-specific type description classes (e.g. cl_abap_elemdescr for elementary -"types, as shown in the hierarchy tree above) -"Using casts, you can access special attributes (i.e. the properties of the respective types). - -"Creating a data reference variable to hold the reference to -"the type description object -DATA ref_elemdescr TYPE REF TO cl_abap_elemdescr. -ref_elemdescr = CAST #( tdo_by_name_elem ). -"Using the older cast operator ?= (which is not used in the examples) -ref_elemdescr ?= tdo_by_name_elem. - -"Alternatives using inline declaration -DATA(ref_elemdescr2) = CAST cl_abap_elemdescr( tdo_by_name_elem ). -"Using method chaining, you can omit extra declarations -DATA(ref_elemdescr3) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_name( 'ELEMTYPE' ) ). -DATA(elem_abs_name) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_name( 'ELEMTYPE' ) )->absolute_name. -"Implementing a check before the cast to the type-specific type description class -IF tdo_by_name_elem IS INSTANCE OF cl_abap_elemdescr. - DATA(ref_elemdescr4) = CAST cl_abap_elemdescr( tdo_by_name_elem ). -ENDIF. - -"Some examples for more detailed information that is accessible after -"the cast. Check the options after the object component selector ->. -DATA(elem_output_length) = ref_elemdescr->output_length. "3 -"The following method checks compatibility of a specified data object -DATA(elem_applies1) = ref_elemdescr->applies_to_data( elemdobj ). "has the value abap_true -DATA test_dobj TYPE c LENGTH 3. -DATA(elem_applies2) = ref_elemdescr->applies_to_data( test_dobj ). "has the value abap_false - -"----------------------------------------------------------------- -"--- Examples using a type description object for a structure ---- -"----------------------------------------------------------------- -DATA ref_structdescr1 TYPE REF TO cl_abap_structdescr. -ref_structdescr1 = CAST #( tdo_by_name_struc ). - -"Check examples before making the cast -"The examples also use inline declaration. -CASE TYPE OF tdo_by_name_struc. - WHEN TYPE cl_abap_structdescr. - DATA(ref_structdescr2) = CAST cl_abap_structdescr( tdo_by_name_struc ). - WHEN OTHERS. - ... -ENDCASE. - -DATA(ref_structdescr3) = COND #( WHEN tdo_by_name_struc IS INSTANCE OF cl_abap_structdescr - THEN CAST cl_abap_structdescr( tdo_by_name_struc ) ). - -"More details accessible after the cast -DATA(struc_kind) = ref_structdescr1->struct_kind. "F (flat) -"The following attribute returns a table with component information, such as -"the component names and type kinds. -DATA(struc_components) = ref_structdescr1->components. -"The following method also returns a table with component information. In this case, -"more information is returned such as type description objects of each component and more. -DATA(struc_components_tab) = ref_structdescr1->get_components( ). - -"----------------------------------------------------------------------- -"--- Examples using a type description object for an internal table ---- -"----------------------------------------------------------------------- -DATA ref_tabledescr1 TYPE REF TO cl_abap_tabledescr. -ref_tabledescr1 = CAST #( tdo_by_name_itab ). -"Cast with inline declaration -DATA(ref_tabledescr2) = CAST cl_abap_tabledescr( tdo_by_name_itab ). - -"Another internal table as an example -DATA itab TYPE SORTED TABLE OF zdemo_abap_carr WITH UNIQUE KEY carrid. -DATA(ref_tabledescr3) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( itab ) ). - -DATA(itab_table_kind) = ref_tabledescr3->table_kind. "O (sorted table) -DATA(itab_has_unique_key) = ref_tabledescr3->has_unique_key. "has the value abap_true -"Returns a table with the names of internal table keys -DATA(itab_table_key) = ref_tabledescr3->key. "carrid -"Returns a table with a description of all table keys, e.g. -"all components of a key, key kind (U, unique, in the example case), -"information whether the key is the primary key etc. -DATA(itab_keys) = ref_tabledescr3->get_keys( ). -"If you want to get information about the line type, e.g. finding out about -"the component names, another cast is required. -"First, getting a reference to the type description object for the structured type. -DATA(itab_line_type) = ref_tabledescr3->get_table_line_type( ). -"Then, performing a cast to access the component information as shown above. -DATA(itab_line_info) = CAST cl_abap_structdescr( itab_line_type ). -DATA(itab_comps1) = itab_line_info->components. -DATA(itab_comps2) = itab_line_info->get_components( ). - -"---------------------------------------------------------------------- -"--- Examples using a type description object for a data reference ---- -"---------------------------------------------------------------------- -DATA ref_refdescr1 TYPE REF TO cl_abap_refdescr. -TYPES type_ref_i TYPE REF TO i. -DATA(tdo_ref) = cl_abap_typedescr=>describe_by_name( 'TYPE_REF_I' ). -ref_refdescr1 = CAST #( tdo_ref ). -DATA(ref_refdescr2) = CAST cl_abap_refdescr( tdo_ref ). - -"Getting a reference to the type description object of a type used to -"type the reference -DATA(ref_type) = ref_refdescr1->get_referenced_type( ). -DATA(ref_abs_name) = ref_refdescr1->get_referenced_type( )->absolute_name. "\TYPE=I - -"------------------------------------------------------------------------- -"--- Examples using a type description object for an object reference ---- -"------------------------------------------------------------------------- -DATA ref_oref1 TYPE REF TO cl_abap_objectdescr. -ref_oref1 = CAST #( tdo_by_oref ). -"See the hierarchy of type description classes. You may also use -"cl_abap_classdescr. -DATA(ref_oref2) = CAST cl_abap_classdescr( tdo_by_oref ). - -"Returns a table with information about the class attributes -DATA(class_attributes) = ref_oref1->attributes. - -"Returns a table with information about the methods such as -"parameters, visibility and more -DATA(class_methods) = ref_oref1->methods. - -"Returns a table with information about the interfaces implemented -DATA(class_intf) = ref_oref1->interfaces. - -"Can class be instantiated -DATA(class_is_inst) = ref_oref1->is_instantiatable( ). "has the value abap_true - -"Using an interface -DATA(tdo_intf) = cl_abap_typedescr=>describe_by_name( 'ZDEMO_ABAP_OBJECTS_INTERFACE' ). -DATA ref_iref TYPE REF TO cl_abap_intfdescr. -ref_iref = CAST #( tdo_intf ). "cl_abap_objectdescr is also possible - -DATA(ref_intf_attr) = ref_iref->attributes. -DATA(ref_intf_meth) = ref_iref->methods. -DATA(ref_intf_attr_objdescr) = CAST cl_abap_objectdescr( tdo_intf )->attributes. -``` - -Excursions: - -```abap -"Casting and method chaining as above in contrast to the following -"extra declarations. If the variables were not declared inline as -"in the example, there would be even more lines of code. -DATA(a) = cl_abap_typedescr=>describe_by_data( some_struc ). -DATA(b) = CAST cl_abap_structdescr( a ). -DATA(c) = b->components. - -"get_included_view method: Getting type information for included -"components, e.g. in case of deep structures -TYPES: BEGIN OF st, - a TYPE i, "elementary type - b TYPE zdemo_abap_carr, "structure - c TYPE string_table, "internal table - END OF st. - -DATA(type_descr) = CAST cl_abap_structdescr( - cl_abap_typedescr=>describe_by_name( 'ST' ) )->get_included_view( ). - -"As mentioned earlier about type name specifications for statements -"such as CREATE DATA, in addition to character-like data objects for -"the type name specified in the parentheses, you can also use absolute -"type names. - -"Type to refer to -TYPES type4abs TYPE p LENGTH 4 DECIMALS 3. - -"Data and object reference variables with generic types -DATA dref4abs TYPE REF TO data. -DATA oref4abs TYPE REF TO object. - -"Getting absolute names -DATA(abs_name_type) = cl_abap_typedescr=>describe_by_name( - 'TYPE4ABS' )->absolute_name. -DATA(abs_name_cl) = cl_abap_typedescr=>describe_by_name( - 'ZCL_DEMO_ABAP_DYNAMIC_PROG' )->absolute_name. - -"Data references -"Named data object holding the absolute name -CREATE DATA dref4abs TYPE (abs_name_type). - -"Unnamed data object -CREATE DATA dref4abs TYPE ('\TYPE=STRING'). - -"Object references -"Named data object -CREATE OBJECT oref4abs TYPE (abs_name_cl). - -"Unnamed data object -CREATE OBJECT oref4abs TYPE ('\CLASS=ZCL_DEMO_ABAP_DYNAMIC_PROG'). -``` - -

⬆️ back to top

- -### Dynamically Creating Data Types at Runtime -You can create data types at program runtime using methods of the type description classes of RTTS. -These types are only valid locally in the program. They are also anonymous, i.e. they are only accessible through type description objects. -As shown above, you can get a reference to a type description object of a type using the static methods of the class `CL_ABAP_TYPEDESCR`. -```abap -"For example, a structured type -DATA(type_descr_obj) = CAST cl_abap_structdescr( - cl_abap_typedescr=>describe_by_name( 'SOME_STRUC_TYPE' ) ). -``` - -The focus here is on using RTTC methods such as `get...`. It is recommended that you use the `get` method instead of the `create` method. - -```abap -"---------------------------------------------------------------------- -"--- Creating type description objects using elementary data types ---- -"---------------------------------------------------------------------- -"Conceptually, all elementary, built-in ABAP types already -"exist and can be accessed by the corresponding get_* methods. -"In ADT, click CTRL + space after cl_abap_elemdescr=>... -"to check out the options. The following examples show a -"selection. - -DATA(tdo_elem_i) = cl_abap_elemdescr=>get_i( ). -DATA(tdo_elem_string) = cl_abap_elemdescr=>get_string( ). - -"For the length specification of type c and others, there is -"an importing parameter available. -DATA(tdo_elem_c_l20) = cl_abap_elemdescr=>get_c( 20 ). - -"Type p with two parameters to be specified. -DATA(tdo_elem_p) = cl_abap_elemdescr=>get_p( p_length = 3 - p_decimals = 2 ). - -"Note: Instead of calling get_i() and others having no importing -"parameters, you could also call the describe_by_name( ) method -"and pass the type names (I‚ STRING etc.) as arguments. -"DATA(tdo_elem_i_2) = CAST cl_abap_elemdescr( -" cl_abap_typedescr=>describe_by_name( 'I' ) ). -"DATA(tdo_elem_string_2) = CAST cl_abap_elemdescr( -" cl_abap_typedescr=>describe_by_name( 'STRING' ) ). - -"---------------------------------------------------------------------- -"--- Creating type description objects using structured data types ---- -"---------------------------------------------------------------------- -"They are created based on a component description table. - -"A structured type such as the following shall be created dynamically -"using a type description object. -TYPES: BEGIN OF struc_type, - a TYPE string, - b TYPE i, - c TYPE c LENGTH 5, - d TYPE p LENGTH 4 DECIMALS 3, - END OF struc_type. - -"Creating a type description object using RTTC method -"Using the get method, you can create the type description object -"dynamically based on a component table. The component table is -"of type abap_component_tab. In this example, the component table -"is created inline. -DATA(tdo_struc) = cl_abap_structdescr=>get( - VALUE #( - ( name = 'A' type = cl_abap_elemdescr=>get_string( ) ) - ( name = 'B' type = cl_abap_elemdescr=>get_i( ) ) - ( name = 'C' type = cl_abap_elemdescr=>get_c( 5 ) ) - ( name = 'D' type = cl_abap_elemdescr=>get_p( p_length = 4 - p_decimals = 3 ) ) ) ). - -"--------------------------------------------------------------------- -"--- Creating type description objects using internal table types ---- -"--------------------------------------------------------------------- -"Note: Specifying the line type is mandatory, the rest is optional. - -"An internal table type such as the following shall be created dynamically -"using a type description object. -TYPES std_tab_type_std_key TYPE STANDARD TABLE OF string WITH DEFAULT KEY. - -"Creating a type description object using RTTC method -"Not specifying the other optional parameters means that the -"default values are used, for example, standard table is the -"default value for p_table_kind. -DATA(tdo_tab_1) = cl_abap_tabledescr=>get( - p_line_type = cl_abap_elemdescr=>get_string( ) ). - -"Another internal table type for which more parameter specifications -"are needed. The following internal table type shall be created using -"a type description object. -TYPES so_table_type TYPE SORTED TABLE OF zdemo_abap_flsch WITH UNIQUE KEY carrid connid. - -"Creating a type description object using RTTC method -"The following example also demonstrates how comfortably constructor -"operators can be used at these positions. -DATA(tdo_tab_2) = cl_abap_tabledescr=>get( - p_line_type = CAST cl_abap_structdescr( - cl_abap_tabledescr=>describe_by_name( 'ZDEMO_ABAP_FLSCH' ) ) - p_table_kind = cl_abap_tabledescr=>tablekind_sorted - p_key = VALUE #( ( name = 'CARRID' ) ( name = 'CONNID' ) ) - p_unique = cl_abap_typedescr=>true ). - -" ... reference types -"Reference types such as the following shall be created using a -"type description object. -TYPES some_ref_type2t TYPE REF TO t. -TYPES some_ref_type2cl TYPE REF TO zcl_demo_abap_dynamic_prog. - -"Using RTTC methods -"You can create a reference type from a base type. This base type -"may be a class, interface or data type. -DATA(tdo_ref_1) = cl_abap_refdescr=>get( cl_abap_elemdescr=>get_t( ) ). -DATA(tdo_ref_2) = cl_abap_refdescr=>get( - cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' ) ). -"Alternative: get_by_name method -DATA(tdo_ref_3) = cl_abap_refdescr=>get_by_name( 'T' ). -DATA(tdo_ref_4) = cl_abap_refdescr=>get_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' ). -``` - -

⬆️ back to top

- -### Dynamically Creating Data Objects at Runtime - -As shown above, anonymous data objects can be dynamically created using `CREATE DATA` statements in many ways by specifying the type ... -- statically: `CREATE DATA dref TYPE string.` -- dynamically: `CREATE DATA dref TYPE (some_type).` - -Another way to dynamically create data objects with dynamic type specification is to use types created at runtime with RTTC methods. -The `CREATE DATA` statement provides the [`TYPE HANDLE`](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm) addition after which you can specify type description objects. A reference variable of the static type of class `CL_ABAP_DATADESCR` or its subclasses that points to a type description object can be specified after `TYPE HANDLE`. - -``` abap -DATA dref_cr TYPE REF TO data. - -"Elementary data object -"Type description object for an elementary type -DATA(tdo_elem_c_l20) = cl_abap_elemdescr=>get_c( 20 ). -"Creating an elementary data object based on a type description object -CREATE DATA dref_cr TYPE HANDLE tdo_elem_c_l20. - -"Structure -DATA(tdo_struc) = cl_abap_structdescr=>get( - VALUE #( - ( name = 'COMP1' type = cl_abap_elemdescr=>get_string( ) ) - ( name = 'COMP2' type = cl_abap_elemdescr=>get_i( ) ) - ( name = 'COMP3' type = cl_abap_elemdescr=>get_c( 3 ) ) ) ). - -"Creating a structure based on a type description object -CREATE DATA dref_cr TYPE HANDLE tdo_struc. - -"Internal table -"In the case below, it is a standard table with standard key by -"default because the other parameters are not specified. -DATA(tdo_tab) = cl_abap_tabledescr=>get( - p_line_type = CAST cl_abap_structdescr( - cl_abap_tabledescr=>describe_by_name( 'ZDEMO_ABAP_CARR' ) ) ). - -"Creating an internal table based on a type description object -CREATE DATA dref_cr TYPE HANDLE tdo_tab. - -"Data reference -DATA(tdo_ref) = cl_abap_refdescr=>get( cl_abap_elemdescr=>get_t( ) ). -CREATE DATA dref_cr TYPE HANDLE tdo_ref. -``` - -

⬆️ back to top

- -## More Information -- It is recommended that you also consult section [Dynamic Programming Techniques (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abendynamic_prog_technique_gdl.htm) in the ABAP Keyword Documentation since it provides important aspects that should be considered when dealing with dynamic programming in general (e. g. security aspects or runtime error prevention). -- There are even further dynamic programming techniques in the unrestricted ABAP language scope [Standard ABAP](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenstandard_abap_glosry.htm) such as the generation or execution of programs at runtime. They are not part of this cheat sheet. Find more details on the related syntax (e. g. `GENERATE SUBROUTINE POOL`, `READ REPORT` and `INSERT REPORT` in the ABAP Keyword Documentation for Standard ABAP: [Dynamic Program Development (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_language_dynamic.htm) - -## Executable Example - -[zcl_demo_abap_dynamic_prog](./src/zcl_demo_abap_dynamic_prog.clas.abap) - -> **💡 Note**
-> - The executable example ... -> - covers the following topics, among others: -> - Field symbols and data references as supporting elements for dynamic programming -> - Dynamic ABAP syntax components -> - Runtime type services (RTTS), i. e. runtime type identification (RTTI) and runtime type creation (RTTC) -> - The steps to import and run the code are outlined [here](README.md#-getting-started-with-the-examples). -> - [Disclaimer](README.md#%EF%B8%8F-disclaimer) + + +# Dynamic Programming + +- [Dynamic Programming](#dynamic-programming) + - [Introduction](#introduction) + - [Excursion: Field Symbols and Data References](#excursion-field-symbols-and-data-references) + - [Field Symbols](#field-symbols) + - [Data References](#data-references) + - [Dynamic ABAP Statements](#dynamic-abap-statements) + - [Dynamic ASSIGN Statements](#dynamic-assign-statements) + - [Dynamically Specifying Data Types/Creating (Data) Objects](#dynamically-specifying-data-typescreating-data-objects) + - [Accessing Structure Components Dynamically](#accessing-structure-components-dynamically) + - [Dynamic Specifications in Statements for Processing Internal Tables](#dynamic-specifications-in-statements-for-processing-internal-tables) + - [Dynamic ABAP SQL Statements](#dynamic-abap-sql-statements) + - [Dynamic Invoke](#dynamic-invoke) + - [Validating Input for Dynamic Specifications (CL\_ABAP\_DYN\_PRG)](#validating-input-for-dynamic-specifications-cl_abap_dyn_prg) + - [Runtime Type Services (RTTS)](#runtime-type-services-rtts) + - [Getting Type Information at Runtime](#getting-type-information-at-runtime) + - [Dynamically Creating Data Types at Runtime](#dynamically-creating-data-types-at-runtime) + - [Dynamically Creating Data Objects at Runtime](#dynamically-creating-data-objects-at-runtime) + - [More Information](#more-information) + - [Executable Example](#executable-example) + +## Introduction + +- Regarding "dynamic" in contrast to "static" aspects, [ABAP programs](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_program_glosry.htm) can include both dynamic and static parts. +- Consider a [data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_object_glosry.htm "Glossary Entry") in your program: + - It can be declared as a [static data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstatic_data_object_glosry.htm), i. e. you provide all attributes by specifying the [data type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_type_glosry.htm) and more statically in the code. + + ```abap + "Internal table declaration + DATA itab TYPE TABLE OF zdemo_abap_carr WITH EMPTY KEY. + ``` + + - The name `itab` of the data object is determined at compile time and remains stable throughout the execution of the program. +- However, there can also be use cases where the attributes of such a data object are not statically determined. This is where dynamic aspects enter the picture: Attributes, names, types etc. are not determined at compile time but rather at runtime. +- There are ABAP statements that include these dynamic aspects in the syntax. Assume you have a simple program and a UI that includes an input field storing the input in a data object named `dbtab`. As input, you expect the name of a database table to be provided. In the end, you want to retrieve all entries of the database table and store them in an internal table. This table should be displayed. So, there is random input at runtime and your program must be able to deal with it. + - See the following `SELECT` statement. The `FROM` clause does not include a statically defined table to be selected from. Instead, there is a pair of parentheses including a data object. It is a character-like data object. Assume the data object holds the name of the database table. At runtime, the data retrieval happens from the database table that was inserted in the input field. + + ```abap + DATA(dbtab) = `ZDEMO_ABAP_FLI`. + + SELECT * + FROM (dbtab) + INTO TABLE @DATA(some_itab). + ``` + +- Further aspects for dynamic programming in ABAP enter the picture if you want to determine information about data types and data objects at runtime ([RTTI](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm)) or even create them ([RTTC](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_creation_glosry.htm)). + +- In general, dynamic programming also comes with some downsides. For example, the ABAP compiler cannot check the dynamic programming feature like the `SELECT` statement mentioned above. There is no syntax warning or suchlike (note the `CL_ABAP_DYN_PRG` class that supports dynamic programming). The checks are performed only at runtime, which has an impact on the performance. Plus, the testing of [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") +that include dynamic programming features may be difficult. + + +

⬆️ back to top

+ +## Excursion: Field Symbols and Data References + +[Field symbols](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfield_symbol_glosry.htm "Glossary Entry") +and [data references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_glosry.htm "Glossary Entry") are covered here since they are supporting elements for dynamic programming. + +### Field Symbols + +Field symbols ... + +- are symbolic names for almost any data object or parts of existing data objects. +- can be assigned actual memory areas at program runtime (using `ASSIGN`). Note that you can only work with the field symbols if indeed they have been assigned before. +- can be used as placeholders for a data object at an [operand position](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenoperand_position_glosry.htm). + - Consider there is a data object in your program. A field symbol is also available that is assigned the memory area of this data object. Accessing a field symbol is like accessing the [named data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abennamed_data_object_glosry.htm) or part of the object itself. +- do not reserve physical space in the [data area](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_area_glosry.htm) of a program like a data object. Instead, they work as dynamic identifiers of a memory area in which a specific data object or part of an object is located. +- can be typed either with [generic data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abengeneric_data_type_glosry.htm "Glossary Entry") or [complete data types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencomplete_data_type_glosry.htm "Glossary Entry"). +- are declared using the statement [`FIELD-SYMBOLS`](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapfield-symbols.htm) or the [declaration operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendeclaration_operator_glosry.htm) [`FIELD-SYMBOL`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfield-symbol_inline.htm). Their names must be included between angle brackets. + +**Declaring field symbols** + +Syntax: +``` abap +"Declaring field symbols using the FIELD-SYMBOLS statement +"and providing a complete/generic type + +"Examples for complete types +FIELD-SYMBOLS: TYPE i, + TYPE zdemo_abap_fli, + TYPE LINE OF some_table_type, + LIKE some_data_object. + +"Examples for generic types (see more examples further down) +FIELD-SYMBOLS TYPE c. "Text field with a generic length +FIELD-SYMBOLS TYPE csequence. "Text-like (c, string) +FIELD-SYMBOLS TYPE data. "Any data type +FIELD-SYMBOLS TYPE any table. "Internal table with any table type + +"Declaring field symbols inline +"In an inline declaration, the typing of the field symbol is done +"with the generic type data. +"Example use case: Inline declaration of a field symbol for an internal table. +LOOP AT itab ASSIGNING FIELD-SYMBOL(). + ... +ENDLOOP. +``` + +> **💡 Note**
+>- After its declaration, a field symbol is initial, i. e. a memory area is not (yet) assigned to it (apart from the inline declaration). If you use an unassigned field symbol, an exception is raised. +>- There are plenty of options for generic ABAP types. A prominent one + is `data` that stands for any data type. See more information in the + topic [Generic ABAP + Types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbuilt_in_types_generic.htm) and in a code snippet below. +>- Field symbols cannot be declared in the declaration part of + [classes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclass_glosry.htm "Glossary Entry") + and + [interfaces](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenoo_intf_glosry.htm "Glossary Entry"). + +**Assigning data objects** + +[`ASSIGN`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapassign.htm) +statements assign the memory area of a data object to a field symbol. +Once the memory area is assigned, you can work with the content. + +``` abap +"Some data object declarations to be used +DATA: num TYPE i, + struc TYPE zdemo_abap_fli, "Demo database table + itab_str TYPE string_table, + itab_fli TYPE TABLE OF zdemo_abap_fli WITH EMPTY KEY. +APPEND INITIAL LINE TO itab_fli. + +"Declaring field symbols with complete types +FIELD-SYMBOLS: TYPE i, + TYPE zdemo_abap_fli, + TYPE string_table. + +"Declaring field symbols with generic type +FIELD-SYMBOLS TYPE data. + +"Assigning data objects to field symbols +"Using field symbols with a static type +ASSIGN num TO . +ASSIGN struc TO . +ASSIGN itab_str TO . +"Using field symbol with a generic type +ASSIGN num TO . +ASSIGN itab_fli TO . +ASSIGN itab_fli[ 1 ] TO . +"Assigning components +ASSIGN struc-carrid TO . +ASSIGN itab_fli[ 1 ]-connid TO . + +"Inline declaration (the field symbol has the type data) +ASSIGN num TO FIELD-SYMBOL(). + +"CASTING addition for matching types of data object and field +"symbol when assigning memory areas +TYPES c_len_3 TYPE c LENGTH 3. +DATA(chars) = 'abcdefg'. + +FIELD-SYMBOLS TYPE c_len_3. + +"Implicit casting +ASSIGN chars TO CASTING. "abc + +FIELD-SYMBOLS TYPE data. + +"Explicit casting +ASSIGN chars TO CASTING TYPE c_len_3. "abc + +DATA chars_l4 TYPE c LENGTH 4. +ASSIGN chars TO CASTING LIKE chars_l4. "abcd +``` + +> **💡 Note**
+> - If you use an unassigned field symbol, an exception is raised. Before using it, you can check the + assignment with the following logical expression. The statement is true if the field symbol is assigned. +> ``` abap +> IF IS ASSIGNED. +>   ... +> ENDIF. +> +> DATA(check) = COND #( WHEN IS ASSIGNED THEN `assigned` ELSE `not assigned` ). +> ``` +>- Using the statement `UNASSIGN`, you can explicitly remove the assignment of the field symbol. A `CLEAR` statement only initializes the value. +> ``` abap +> UNASSIGN . +> ``` +>- See more information on the addition `CASTING` [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapassign_casting.htm). + +**Examples using field symbols** + +``` abap +"Assignments +DATA num TYPE i VALUE 1. +FIELD-SYMBOLS TYPE i. +ASSIGN num TO . + + = 2. +"The data object 'num' has now the value 2. + +"Loops +"Here, field symbols are handy since you can avoid an +"actual copying of the table line. +SELECT * + FROM zdemo_abap_fli + INTO TABLE @DATA(itab). + +FIELD-SYMBOLS LIKE LINE OF itab. + +LOOP AT itab ASSIGNING . + -carrid = ... "The field symbol represents a line of the table. + -connid = ... "Components are accessed with the component selector. + "Here, it is assumed that a new value is assigned. + ... +ENDLOOP. + +"Inline declaration of a field symbol. The field symbol is implcitly typed +"with the generic type data. +LOOP AT itab ASSIGNING FIELD-SYMBOL(). + -carrid = ... + -connid = ... + ... +ENDLOOP. + +"----------- Generic typing ----------- +"- Generic types are available with which formal parameters of methods or field symbols +" can be specified. +"- At runtime, the actual data type is copied from the assigned actual parameter or +" memory area, i.e. they receive the complete data type only when an actual parameter +" is passed or a memory area is assigned. + +"The following code snippet demonstrates generic types with field symbols. +FIELD-SYMBOLS: + "Any data type + TYPE data, + TYPE any, + "Any data type can be assigned. Restrictions for formal parameters and 'data': no + "numeric functions, no description functions, and no arithmetic expressions can be + "passed to these parameters. However, you can bypass the restriction by applying the + "CONV operator for the actual parameter. + + "Character-like types + TYPE c, "Text field with a generic length + TYPE clike, "Character-like (c, n, string, d, t and character-like flat structures) + TYPE csequence, "Text-like (c, string) + TYPE n, "Numeric text with generic length + TYPE x, "Byte field with generic length + TYPE xsequence, "Byte-like (x, xstring) + + "Numeric types + TYPE decfloat, "decfloat16, decfloat34) + TYPE numeric, "Numeric ((b, s), i, int8, p, decfloat16, decfloat34, f) +

TYPE p, "Packed number (generic length and number of decimal places) + + "Internal table types + TYPE ANY TABLE, "Internal table with any table type + TYPE HASHED TABLE, + TYPE INDEX TABLE, + TYPE SORTED TABLE, + TYPE STANDARD TABLE, +

TYPE table, "Standard table + + "Other types + TYPE simple, "Elementary data type including enumerated types and + "structured types with exclusively character-like flat components + TYPE REF TO object. "object can only be specified after REF TO; can point to any object + +"Data objects to work with +DATA: BEGIN OF s, + c3 TYPE c LENGTH 3, + c10 TYPE c LENGTH 10, + n4 TYPE n LENGTH 4, + str TYPE string, + time TYPE t, + date TYPE d, + dec16 TYPE decfloat16, + dec34 TYPE decfloat34, + int TYPE i, + pl4d2 TYPE p LENGTH 4 DECIMALS 2, + tab_std TYPE STANDARD TABLE OF string WITH EMPTY KEY, + tab_so TYPE SORTED TABLE OF string WITH NON-UNIQUE KEY table_line, + tab_ha TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line, + xl1 TYPE x LENGTH 1, + xstr TYPE xstring, + structure TYPE zdemo_abap_carr, "character-like flat structure + oref TYPE REF TO object, + END OF s. + +"The following static ASSIGN statements demonstrate various assignments +"Note: +"- The statements commented out show impossible assignments. +"- If a static assignment is not successful, sy-subrc is not set and no +" memory area is assigned. Dynamic assignments, however, set the value. + +"----- Any data type ----- +ASSIGN s-c3 TO . +ASSIGN s-time TO . +ASSIGN s-tab_std TO . +ASSIGN s-xstr TO . +ASSIGN s-pl4d2 TO . +ASSIGN s-date TO . +ASSIGN s TO . + +"----- Character-like types ----- +ASSIGN s-c3 TO . +ASSIGN s-c10 TO . +"ASSIGN s-str TO . + +ASSIGN s-c10 TO . +ASSIGN s-str TO . +ASSIGN s-n4 TO . +ASSIGN s-date TO . +ASSIGN s-time TO . +ASSIGN s-structure TO . + +ASSIGN s-c10 TO . +ASSIGN s-str TO . +"ASSIGN s-n4 TO . + +ASSIGN s-n4 TO . +"ASSIGN s-int TO . +"ASSIGN s-time TO . + +ASSIGN s-xl1 TO . +"ASSIGN s-xstr TO . + +ASSIGN s-xl1 TO . +ASSIGN s-xstr TO . + +"----- Numeric types ----- +ASSIGN s-dec16 TO . +ASSIGN s-dec34 TO . +ASSIGN s-int TO . +ASSIGN s-pl4d2 TO . +"ASSIGN s-n4 TO . + +ASSIGN s-dec16 TO . +ASSIGN s-dec34 TO . + +ASSIGN s-pl4d2 TO

. +"ASSIGN s-dec34 TO

. + +"----- Internal table types ----- +ASSIGN s-tab_std TO . +ASSIGN s-tab_so TO . +ASSIGN s-tab_ha TO . + +ASSIGN s-tab_std TO . +ASSIGN s-tab_so TO . +"ASSIGN s-tab_ha TO . + +"ASSIGN s-tab_std TO . +ASSIGN s-tab_so TO . +"ASSIGN s-tab_ha TO . + +ASSIGN s-tab_std TO . +ASSIGN s-tab_std TO

. +"ASSIGN s-tab_so TO . +"ASSIGN s-tab_so TO
. +"ASSIGN s-tab_ha TO . +"ASSIGN s-tab_ha TO
. + +"ASSIGN s-tab_std TO . +"ASSIGN s-tab_so TO . +ASSIGN s-tab_ha TO . + +"----- Other types ----- +ASSIGN s-c10 TO . +ASSIGN s-str TO . +ASSIGN s-dec34 TO . +ASSIGN s-date TO . +ASSIGN s-structure TO . +ASSIGN s-xl1 TO . +"ASSIGN s-tab_ha TO . + +ASSIGN s-oref TO . +s-oref = NEW zcl_demo_abap_objects( ). +``` + +

⬆️ back to top

+ +### Data References + +[Data references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_glosry.htm "Glossary Entry") +... + +- are references that point to any data object or to their parts (for example, components, lines of internal tables). +- are contained in [data reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_variable_glosry.htm "Glossary Entry") + in ABAP programs. + +[Data reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_reference_variable_glosry.htm "Glossary Entry") +... + +- are data objects that contain a reference. +- are "opaque", i. e. the contained references cannot be accessed directly. To access the content, these variables must be dereferenced first. +- are [deep](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendeep_glosry.htm "Glossary Entry") data objects like strings and internal tables. +- are typed with the addition [`REF TO`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abaptypes_references.htm) followed by a [static type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstatic_type_glosry.htm). Note the [dynamic type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendynamic_type_glosry.htm) in this context: The dynamic type of such a variable is the data type to which it actually points. This concept is particularly relevant in the context of assignments (see the assignment rules [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconversion_references.htm)). +- can be typed with a complete or generic type. However, only `data` can be used as generic type. + +> **💡 Note**
+> [Object references](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_reference_glosry.htm "Glossary Entry") +and [object reference variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_refer_variable_glosry.htm "Glossary Entry") are not part of this cheat sheet. To get more details, refer to the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_reference_type.htm) or the cheat sheet [ABAP Object Orientation](04_ABAP_Object_Orientation.md). + +**Declaring data reference variables** + +``` abap +"Example declarations of data reference variables with static types. +"The static types can be complete or generic (but only data can be used). +"Note that they do not yet point to a data object. At this stage, +"initial reference variables contain null references. +DATA: ref_a TYPE REF TO i, "Complete data type + ref_b TYPE REF TO some_dbtab, "Complete data type + ref_c LIKE REF TO some_data_object, + ref_d TYPE REF TO data, "Generic data type + ref_e LIKE ref_a. "Referring to an existing data reference variable +``` + +As shown below, instead of the explicit declaration, inline declarations are also possible. +See also the cheat sheet [Data Types and Data Objects](16_Data_Types_and_Objects.md). + +**Assigning references to existing data objects** using the +[reference operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenreference_operator_glosry.htm "Glossary Entry") +`REF`. +``` abap +"Declaring a data object +DATA num TYPE i VALUE 5. + +"Declaring data reference variables +DATA ref1 TYPE REF TO i. +DATA ref_gen TYPE REF TO data. + +"Creating data references to data objects. +"The # character stands for a data type that is determined in the +"following hierarchy: +"- If the data type required in an operand position is unique and +" known completely, the operand type is used. +"- If the operand type cannot be derived from the context, the +" data type of the data object within the parentheses is used. +"- If the data type of the data object within the parentheses is +" not known statically, the generic type data is used. + +ref1 = REF #( num ). +ref_gen = REF #( num ). + +"Creating a data reference variable inline. +"Note: No empty parentheses can be specified after REF. +DATA(ref2) = REF #( num ). + +"Data reference variable of type ref to data by specifying the +"generic type data after REF +DATA(ref3) = REF data( ... ). + +"A non-generic type can be used; only if an upcast works (see +"upcasts below) +DATA(ref3) = REF some_type( ... ). + +"The older syntax GET REFERENCE having the same effect should +"not be used anymore. +"GET REFERENCE OF num INTO ref1. +"GET REFERENCE OF num INTO DATA(ref5). +``` + +**Creating new data objects at runtime**: +[Anonymous data objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenanonymous_data_object_glosry.htm "Glossary Entry") ... +- are dynamically created at runtime. +- are relevant if the data type is only known when the program is executed. +- cannot be addressed by a name ("anonymous"). +- expect a data reference variable when declared. The content of an anonymous data object can only be accessed using dereferenced variables as shown below or field symbols. +- can be created using the statement [`CREATE DATA`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_data.htm), the instance operator [`NEW`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expression_new.htm), or the addition [`NEW`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_into_target.htm) of the `INTO` clause in a `SELECT` statement. + +> **💡 Note**
+> The following snippet covers statically defined types. Data objects can also be created with `CREATE DATA` dynamically using dynamic type definitions (the type name is specified within a pair of parentheses) and type description objects ([`TYPE HANDLE` addition](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm)) as shown further down. +> Using [`CREATE OBJECT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object.htm) statements, you can create an object as an instance of a class and assign the reference to the object to an [object reference variable](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_refer_variable_glosry.htm). Find more information in the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object.htm). + +```abap +"CREATE DATA statements +"Note that there are many additions available. The examples +"show a selection. Behind TYPE and LIKE, the syntax offers +"the same possibilities as the DATA statement. + +"Creating an anonymous data object with an implicit type. +"If neither of the additions TYPE or LIKE are specified, the +"data reference variable must be completely typed. +DATA dref_1 TYPE REF TO string. +CREATE DATA dref_1. + +"Creating anonymous data objects with explicit data type +"specification. +"Data reference variable with a generic type to be used in +"the following examples for the anonymous data object. +DATA dref_2 TYPE REF TO data. + +"Elementary, built-in ABAP type +CREATE DATA dref_2 TYPE p LENGTH 8 DECIMALS 3. + +"Anomyous internal table ... +"using the LIKE addition to refer to an existing internal table +DATA itab TYPE TABLE OF zdemo_abap_carr. +CREATE DATA dref_2 LIKE itab. + +"by specifying the entire table type +CREATE DATA dref_2 TYPE HASHED TABLE OF zdemo_abap_carr + WITH UNIQUE KEY carrid. + +"Anonymous structures +CREATE DATA dref_2 LIKE LINE OF itab. +CREATE DATA dref_2 TYPE zdemo_abap_carr. + +"Creating reference variable +CREATE DATA dref_2 TYPE REF TO itab. + +"NEW operator +"- Works like CREATE DATA dref TYPE type statements and can +" be used in general expression positions. +"- Allows to assign values to the new anonymous data objects +" in parentheses + +"Creating data reference variables +DATA: dref_3 TYPE REF TO i, + dref_4 TYPE REF TO data. + +"# character after NEW if the data type can be identified +"completely instead of the explicit type specification (only +"non-generic types possible) +dref_3 = NEW #( 123 ). +dref_3 = NEW i( 456 ). +dref_4 = NEW zdemo_abap_carr( ). "not assigning any values +dref_4 = NEW string( `hi` ). + +"Creating anonymous data objects inline +"In doing so, you can omit a prior declaration of a variable. +DATA(dref_5) = NEW i( 789 ). +DATA(dref_6) = NEW zdemo_abap_carr( carrid = 'AB' + carrname = 'AB Airlines' ). + +"ABAP SQL SELECT statements +"Using the NEW addition in the INTO clause, an anonymous data +"object can be created in place. +SELECT * + FROM zdemo_abap_carr + INTO TABLE NEW @DATA(dref_7). "internal table + +SELECT SINGLE * + FROM zdemo_abap_carr + INTO NEW @DATA(dref_8). "structure +``` + +**Assignments between two data reference variables**. As mentioned above regarding the assignment, note that static types of both data +reference variables must be compatible. As a result of an assignment, both the target reference variable and the source reference variable point to the same data object. + +Excursion: Static vs. dynamic type, upcasts and downcasts +- Data reference variables have ... + - a [static type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstatic_type_glosry.htm "Glossary Entry"). This is the type you specify when declaring the variable, i. e. `i` is the static type in this example: `DATA ref TYPE REF TO i.`. The static type can also be a generic data type: `DATA ref TYPE REF TO data.`. + - a [dynamic type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendynamic_type_glosry.htm "Glossary Entry"), the type of a data object to which the reference variable actually points to at runtime. +- For an assignment to work, the differentiation is particularly relevant since the following basic rule applies: The static type of the target reference variable must be more general than or the same as the dynamic type of the source reference variable. + +- This is where the concepts of [upcast](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenup_cast_glosry.htm "Glossary Entry") and [downcast](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendown_cast_glosry.htm "Glossary Entry") enter the picture. + - Up and down? This concept originates from the idea of moving up or down in an [inheritance tree](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninheritance_tree_glosry.htm). In an assignment between reference variables, the target variable inherits the dynamic type of the source variable. + - Upcast: If the static type of the target variables is **less specific or the same** as the static type of the source variable, an assignment is possible. This includes, for example, assignments with the [assignment operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenassignment_operator_glosry.htm) `=`. + - Downcast: If the static type of the target variable is **more specific** than the static type of the source variable, a check must be made at runtime before the assignment is done. If you indeed want to trigger such a downcast, you must do it explicitly in your code. You can do this, for example, using the + [constructor operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_operator_glosry.htm "Glossary Entry") +[`CAST`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expression_cast.htm). In older code, you may see the use of the [`?=`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmove_cast.htm) operator. + - In contrast to a downcast, an upcast does not have to be done explicitly. However, you can - but need not - use the mentioned operators for upcasts, too. + + +``` abap +"Examples demonstrating up- and downcasts + +"Declaring data reference variables +DATA ref1 TYPE REF TO i. +DATA ref2 TYPE REF TO i. + +ref1 = NEW #( 789 ). + +"Assignments +ref2 = ref1. + +"Casting + +"Complete type +DATA(ref3) = NEW i( 321 ). + +"Generic type +DATA ref4 TYPE REF TO data. + +"Upcast +ref4 = ref3. + +"Downcasts +DATA ref5 TYPE REF TO i. + +"Generic type +DATA ref6 TYPE REF TO data. + +ref6 = NEW i( 654 ). +ref5 = CAST #( ref6 ). + +"Casting operator in older syntax +"ref5 ?= ref6. + +"Note: The cast operators can also but need not be specified for upcasts. +ref4 = CAST #( ref3 ). +``` + +**Addressing data references** + +Before addressing the content of data objects a data reference points to, you must dereference data reference variables. Use the +[dereferencing operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendereferencing_operat_glosry.htm "Glossary Entry") +`->*`. To check if dereferencing works, you can use a logical expression with [`IS BOUND`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenlogexp_bound.htm). + +``` abap +"Creating data reference variables and assign values + +DATA(ref_i) = NEW i( 1 ). +DATA(ref_carr) = NEW zdemo_abap_carr( carrid = 'LH' carrname = 'Lufthansa' ). + +"Generic type + +DATA ref_gen TYPE REF TO data. +ref_gen = ref_i. "Copying reference + +"Accessing + +"Variable number receives the content. +DATA(number) = ref_i->*. + +"Content of referenced data object is changed. +ref_i->* = 10. + +"Data reference used in a logical expression. +IF ref_i->* > 5. + ... +ENDIF. + +"Dereferenced generic type +DATA(calc) = 1 + ref_gen->*. + +"Structure +"Complete structure +DATA(struc) = ref_carr->*. + +"When dereferencing a data reference variable that has a structured +"data type, you can use the component selector -> to address individual components +DATA(carrid) = ref_carr->carrid. +ref_carr->carrid = 'UA'. + +"This longer syntax with the dereferencing operator also works. +ref_carr->*-carrname = 'United Airlines'. + +"Checking if a data reference variable can be dereferenced. +IF ref_carr IS BOUND. +  ... +ENDIF. + +DATA(ref_bound) = COND #( WHEN ref_carr IS BOUND THEN ref_carr->carrid ELSE `is not bound` ). + +"Explicitly removing a reference +"However, the garbage collector takes care of removing the references +"automatically once the data is not used any more by a reference. +CLEAR ref_carr. +``` + +**Excursion: Generic data references and field symbols** + +```abap +"Non-generic type +DATA ref_int TYPE REF TO i. +ref_int = NEW #( ). +ref_int->* = 123. + +"Generic type +DATA ref_generic TYPE REF TO data. +ref_generic = NEW i( ). "Syntax in modern ABAP +CREATE DATA ref_generic TYPE i. "Syntax for older ABAP releases + +"As mentioned above, the content of anonymous data objects can only be +"accessed using dereferenced data variables and field symbols. +"The only option to access the variable in older releases was via field symbols. +ASSIGN ref_generic->* TO FIELD-SYMBOL(). + = 123. + +"An access as the following, as it is possible in modern ABAP, was not possible. +ref_generic->* = 123. + +"In modern ABAP, variables and field symbols of the generic types +"'any' and 'data' can be used directly, for example, in LOOP and READ statements. +DATA dref TYPE REF TO data. +CREATE DATA dref TYPE TABLE OF zdemo_abap_carr. +SELECT * + FROM zdemo_abap_carr + INTO TABLE @dref->*. + +"Note: In case of a fully generic type, an explicit or implicit index operation +"is not possible (indicated by the examples commented out). +LOOP AT dref->* ASSIGNING FIELD-SYMBOL(). + ... +ENDLOOP. +"LOOP AT dref->* ASSIGNING FIELD-SYMBOL() FROM 1 TO 4. +"ENDLOOP. + +"The following examples use a dynamic key specification. +"See more syntax examples below. +READ TABLE dref->* ASSIGNING FIELD-SYMBOL() WITH KEY ('CARRID') = 'AA'. +"READ TABLE dref->* INDEX 1 ASSIGNING FIELD-SYMBOL(). + +"Table expressions +DATA(line) = CONV zdemo_abap_carr( dref->*[ ('CARRID') = 'AA' ] ). +dref->*[ ('CARRID') = 'AA' ] = VALUE zdemo_abap_carr( BASE dref->*[ ('CARRID') = 'AA' ] carrid = 'XY' ). +dref->*[ ('CARRID') = 'XY' ]-('CARRID') = 'ZZ'. + +"Table functions +DATA(num_tab_lines) = lines( dref->* ). +DATA(idx) = line_index( dref->*[ ('CARRID') = 'LH' ] ). +``` + +**Examples using data references** + +Some example contexts of using data references are as follows: + +*Overwriting data reference variables*: +``` abap +dref = NEW i( 1 ). + +"ref is overwritten here because a new object is created +"with a data reference variable already pointing to a data object +dref = NEW i( 2 ). +``` + +*Retaining data references*: + +``` abap +"This snippet shows that three data references are created +"with the same reference variable. Storing them in an internal table +"using the type TYPE TABLE OF REF TO prevents the overwriting. + +DATA: dref TYPE REF TO data, + itab TYPE TABLE OF REF TO data, + num TYPE i VALUE 0. + +DO 3 TIMES. + "Adding up 1 to demonstrate a changed data object. + num += 1. + + "Creating data reference and assigning value. + "In the course of the loop, the variable gets overwritten. + dref = NEW i( num ). + + "Adding the reference to itab + itab = VALUE #( BASE itab ( dref ) ). +ENDDO. +``` + +*Processing internal tables*: + +``` abap +"Similar use case to using field symbols: In a loop across an internal table, +"you assign the content of the line in a data reference variable +"instead of actually copying the content to boost performance. +"Again, the inline declaration comes in handy. + +"Filling an internal table. +SELECT * + FROM zdemo_abap_fli + INTO TABLE @DATA(fli_tab). + +LOOP AT fli_tab REFERENCE INTO DATA(ref). + + "A component of the table line may be addressed. + "Note the object component selector; the dereferencing operator together + "with the component selector is also possible: ->*- + ref->carrid = ... + ... +ENDLOOP. + +"More statements are available that assign content to a data reference variable, +"for example, READ TABLE. +READ TABLE fli_tab INDEX 1 REFERENCE INTO DATA(rt_ref). +``` + +*Data reference variables as part of structures and internal tables*: +``` abap +"Unlike field symbols, data reference variables can be used as +"components of structures or columns in internal tables. + +"Structure +DATA: BEGIN OF struc, + num TYPE i, + ref TYPE REF TO i, + END OF struc. + +"Some value assignment + +struc = VALUE #( num = 1 ref = NEW #( 2 ) ). + +"Internal table + +DATA itab LIKE TABLE OF struc WITH EMPTY KEY. +APPEND struc TO itab. +itab[ 1 ]-ref->* = 123. +``` + +> **✔️ Hint**
+> When to actually use either a field symbol +or a data reference variable? It depends on your use case. However, data +reference variables are more powerful as far as their usage options are +concerned, and they better fit into the modern (object-oriented) ABAP +world. Recommended read: [Accessing Data Objects Dynamically (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abendyn_access_data_obj_guidl.htm "Guideline"). + +

⬆️ back to top

+ +## Dynamic ABAP Statements + +As already mentioned above, there are ABAP statements that support the dynamic specification of syntax elements. +In this context, you can usually use elementary, character-like data objects specified within a pair of parentheses. +For example, `SORT` statements: +``` abap +"Named, character-like data object specified within parentheses +"used by an ABAP statement +DATA(field_name) = 'CARRNAME'. +SORT itab BY (field_name). + +"Unnamed, character-like data object specified within parentheses +SORT itab BY ('CURRCODE'). +``` + +Note that dynamically specifying syntax elements has downsides, too. Consider some erroneous character-like content of such data objects. There is no syntax warning. At runtime, it can lead to runtime errors. +Some of the following code snippets use artifacts from the cheat sheet repository. The code snippets demonstrate a selection. + +### Dynamic ASSIGN Statements + +``` abap +"Creating and populating various types/data objects to work with +TYPES: BEGIN OF st_type, + col1 TYPE i, + col2 TYPE string, + col3 TYPE string, + END OF st_type. +DATA st TYPE st_type. +DATA it TYPE TABLE OF st_type WITH EMPTY KEY. +st = VALUE #( col1 = 1 col2 = `aaa` col3 = `Z` ). +APPEND st TO it. +DATA(dref) = NEW st_type( col1 = 2 col2 = `b` col3 = `Y` ). +DATA dobj TYPE string VALUE `hallo`. +"The following examples use a field symbol with generic type +FIELD-SYMBOLS TYPE data. + +"------- Specifying the memory area dynamically ------ +"I.e. the memory area is not specified directly, but as content of a +"character-like data object in parentheses. +"Note: +"- When specified as unnamed data object, the compiler treats the +" specifications like static assignments. Do not use named data objects +" for ASSIGN statements in ABAP for Cloud Development. It is recommended +" that existing named data objects are put in a structure. Then, the syntax +" for assigning components dynamically can be used so as to avoid a syntax +" warning. +"- Most of the following examples use an unnamed data object. +"- The specification of the name is not case-sensitive. + +ASSIGN ('IT') TO . +ASSIGN ('ST') TO . + +"Field symbol declared inline +"Note: The typing is performed with the generic type data. +ASSIGN ('DOBJ') TO FIELD-SYMBOL(). + +"The statements set the sy-subrc value. +ASSIGN ('DOES_NOT_EXIST') TO . +IF sy-subrc <> 0. + ... +ENDIF. + +"The memory area can also be a dereferenced data reference +ASSIGN dref->* TO . + +"------- Assigning components dynamically ------ +"You can chain the names with the component selector (-), or, in +"case of reference variables, the object component selector (->). +ASSIGN st-('COL1') TO . +ASSIGN it[ 1 ]-('COL1') TO . +ASSIGN dref->('COL1') TO . +"The following example uses the dereferencing operator explicitly +"followed by the component selector. +ASSIGN dref->*-('COL1') TO . + +"Using a named data object for the component specification +DATA columnname TYPE string VALUE `COL1`. +ASSIGN st-(columnname) TO . + +"Fully dynamic specification +"If the compiler can fully determine the data object in ASSIGN statements +"in ABAP for Cloud Development, a warning is not issued. +ASSIGN ('ST-COL1') TO . + +"Numeric expressions are possible. Its value is interpreted +"as the position of the component in the structure. +ASSIGN st-(3) TO . + +"If the value is 0, the memory area of the entire structure is +"assigned to the field symbol. +ASSIGN st-(0) TO . + +"The statements above replace the following, older statements. +ASSIGN COMPONENT 'COL1' OF STRUCTURE st TO . +ASSIGN COMPONENT 3 OF STRUCTURE st TO . + +"------- Assigning attributes of classes or interfaces dynamically ------ +"The following syntax pattern shows the possible specifications. +"... cref->(attr_name) ... "object reference variable +"... iref->(attr_name) ... "interface reference variable +"... (clif_name)=>(attr_name) ... "class/interface name +"... (clif_name)=>attr ... +"... clif=>(attr_name) ... + +"Creating an instance of a class +DATA(oref) = NEW zcl_demo_abap_objects( ). + +"Assigning instance attributes using an object reference variable +"All visible attributes of objects can be assigned. +oref->string = `ABAP`. "Assigning a value to the attribute for demo purposes +ASSIGN oref->('STRING') TO . + +"Assigning instance attributes using an interface reference variable +DATA iref TYPE REF TO zdemo_abap_objects_interface. +iref = oref. +ASSIGN iref->('STRING') TO . +iref->in_str = `hallo`. +ASSIGN iref->('IN_STR') TO . + +"Assigning static attributes +"All visible static attributes in classes and interfaces can be assigned +"In the following example, a class and an interface are specified statically, +"and the attributes are specified dynamically. +ASSIGN zcl_demo_abap_objects=>('PUBLIC_STRING') TO . +ASSIGN zdemo_abap_objects_interface=>('CONST_INTF') TO . + +"Specifying a class or interface dynamically, and attributes statically +ASSIGN ('ZCL_DEMO_ABAP_OBJECTS')=>public_string TO . +ASSIGN ('ZDEMO_ABAP_OBJECTS_INTERFACE')=>const_intf TO . + +"Specifying a class or interface as well as attributes dynamically +ASSIGN ('ZCL_DEMO_ABAP_OBJECTS')=>('PUBLIC_STRING') TO . +ASSIGN ('ZDEMO_ABAP_OBJECTS_INTERFACE')=>('CONST_INTF') TO . + +"Further dynamic syntax options are possible, for example, +"specifying the memory area after ASSIGN with a writable expression +"because the operand position after ASSIGN is a result position. +ASSIGN NEW zcl_demo_abap_objects( )->('PUBLIC_STRING') TO . + +"ELSE UNASSIGN addition +"If ELSE UNASSIGN is specified in the context of dynamic assignments/accesses, +"no memory area is assigned to the field symbol. It is unassigned after +"the ASSIGN statement. +"Note: For the static variant of the ASSIGN statement, i.e. if the memory area +"to be assigned following the ASSIGN keyword is statically specified, the addition +"ELSE UNASSIGN is implicitly set and cannot be used explicitly. +DATA(hallo) = `Hallo world`. +ASSIGN ('HALLO') TO FIELD-SYMBOL() ELSE UNASSIGN. +ASSERT sy-subrc = 0 AND IS ASSIGNED. +ASSIGN ('DOES_NOT_EXIST') TO ELSE UNASSIGN. +ASSERT sy-subrc = 4 AND IS NOT ASSIGNED. +``` + +> **💡 Note**
+> - The following `ASSIGN` statements set the `sy-subrc` value: dynamic assignments, dynamic component assignment, dynamic invokes, assignments of table expressions. +> - The return code is not set for a static assignment and an assignment of the constructor operator `CAST`. + +

⬆️ back to top

+ +### Dynamically Specifying Data Types/Creating (Data) Objects + +- For dynamic syntax elements in `CREATE OBJECT` statements, find more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcreate_object_explicit.htm) (note that parameters can be specified dynamically, too). +- In addition to character-like data objects for the type name specified in the parentheses, you can also use [absolute type names](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabsolute_typename_glosry.htm) (see the information about RTTI below). + +``` abap +"Anonymous data objects are created using a type determined at +"runtime. See more information below. Note that the NEW operator +"cannot be used here. +DATA(some_type) = 'STRING'. +DATA dataref TYPE REF TO data. +CREATE DATA dataref TYPE (some_type). +CREATE DATA dataref TYPE TABLE OF (some_type). +CREATE DATA dataref TYPE REF TO (some_type). +"Using an absolute type name +CREATE DATA dataref TYPE ('\TYPE=STRING'). + +"Assigning a data object to a field symbol casting a dynamically +"specified type +TYPES clen5 TYPE c LENGTH 5. +DATA: dobj_c10 TYPE c LENGTH 10 VALUE '1234567890', + some_struct TYPE zdemo_abap_fli. +FIELD-SYMBOLS TYPE data. + +ASSIGN dobj_c10 TO CASTING TYPE ('CLEN5'). "12345 +ASSIGN dobj_c10 TO CASTING LIKE some_struct-('CARRID'). "123 + +"Dynamically creating an object as an instance of a class and +"assigning the reference to the object to an object reference +"variable. oref can be an object or interface reference variable. +"The reference variable is created here with the generic 'object'. +DATA oref_dyn TYPE REF TO object. +CREATE OBJECT oref_dyn TYPE ('ZCL_DEMO_ABAP_OBJECTS'). +"Accessing an instance attribute +oref_dyn->('ANOTHER_STRING') = `hi`. + +"Note: As covered further down and in the executable example, +"CREATE DATA and ASSIGN statements have the HANDLE addition +"after which dynamically created types can be specified. A type +"description object is expected. + +"Getting type description object +DATA(tdo_elem) = cl_abap_elemdescr=>get_c( 4 ). +CREATE DATA dataref TYPE HANDLE tdo_elem. +dataref->* = dobj_c10. "1234 +ASSIGN dobj_c10 TO CASTING TYPE HANDLE tdo_elem. "1234 +``` + +

⬆️ back to top

+ +### Accessing Structure Components Dynamically + +``` abap +"Creating and populating various types/data objects to work with +TYPES: BEGIN OF st_type, + col1 TYPE i, + col2 TYPE string, + col3 TYPE string, + END OF st_type. +DATA st TYPE st_type. +DATA it TYPE TABLE OF st_type WITH EMPTY KEY. +st = VALUE #( col1 = 1 col2 = `aaa` col3 = `Z` ). +APPEND st TO it. +DATA(dref) = NEW st_type( col1 = 2 col2 = `b` col3 = `Y` ). + +"You can achieve the access using ASSIGN statements as shown above, or +"by statically specifying the structure and the (object) component selector +"followed by a character-like data object in parentheses. +"Write position +st-('COL1') = 123. +it[ 1 ]-('COL1') = 456. +dref->('COL1') = 789. + +"Read position +"The example shows how you can retrieve the textual content of any component +"of any structure. +DATA(content_col2) = CONV string( st-('COL1') ). +DATA(content_col3) = |{ st-('COL3') }|. +DATA content_col1 LIKE st-col1. +content_col1 = st-('COL1'). + +DATA dref_comp TYPE REF TO data. +CREATE DATA dref_comp LIKE st-('COL3'). +dref_comp->* = st-('COL3'). + +"If the component is not found, a catchable exception is raised. +TRY. + DATA(col_not_existent) = |{ st-('COL123') }|. + CATCH cx_sy_assign_illegal_component. + ... +ENDTRY. + +"Accessing components of generic structures dynamically, +"e.g. if you have a method parameter that is typed with the generic type +"data. +"The example uses a field symbol with the generic type data which is assigned +"a structure. +FIELD-SYMBOLS TYPE data. +ASSIGN st TO . + +"As in the examples above, specifying components dynamically is possible. +-('COL2') = `ABAP`. +DATA(gen_comp) = CONV string( -('COL2') ). + +"Excursion +"In the following example, a structure is assigned to a field symbol that +"has a generic type. The components of the structure are accessed dynamically in +"a DO loop. The sy-index value is interpreted as the position of the component +"in the structure. Plus, using RTTI - as also shown further down - the component +"names are retrieved. Component names and the values are added to a string. As a +"prerequisite, all component values must be convertible to type string. +DATA struc2string TYPE string. +FIELD-SYMBOLS TYPE data. +ASSIGN st TO . +IF sy-subrc = 0. + TRY. + DATA(comps) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( ) )->components. + DO. + TRY. + DATA(comp_name) = comps[ sy-index ]-name. + struc2string = struc2string && + COND #( WHEN sy-index <> 1 THEN `, ` ) && + comp_name && `: "` && + -(sy-index) && `"`. + CATCH cx_sy_assign_illegal_component cx_sy_itab_line_not_found. + EXIT. + ENDTRY. + ENDDO. + CATCH cx_sy_move_cast_error. + ENDTRY. +ENDIF. +"struc2string: COL1: "123", COL2: "ABAP", COL3: "Z" +``` + +

⬆️ back to top

+ +### Dynamic Specifications in Statements for Processing Internal Tables + +```abap +"Creating and populating various types/data objects to work with +TYPES: BEGIN OF demo_struct, + col1 TYPE i, + col2 TYPE string, + col3 TYPE string, + END OF demo_struct. +DATA itab_ek TYPE TABLE OF demo_struct WITH EMPTY KEY. +"Standard table and specification of primary and secondary table key +DATA itab TYPE TABLE OF demo_struct + WITH NON-UNIQUE KEY col1 + WITH UNIQUE SORTED KEY sk COMPONENTS col2. +TYPES itab_type LIKE itab. +DATA itab_ref TYPE TABLE OF REF TO demo_struct WITH EMPTY KEY. +itab_ek = VALUE #( ( col1 = 1 col2 = `aaa` col3 = `zzz` ) + ( col1 = 2 col2 = `bbb` col3 = `yyy` ) + ( col1 = 3 col2 = `ccc` col3 = `xxx` ) ). +itab = itab_ek. +itab_ref = VALUE #( ( NEW demo_struct( col1 = 1 col2 = `aaa` col3 = `zzz` ) ) ). + +"Notes +"- In statements using key specifications, secondary table key names (or alias names) +" are usually specified. Also the primary table key using the predefined name +" primary_key or its alias name can be used. +"- Many of the following statements provide similar additions offering dynamic +" specifications, such as USING KEY and dynamic component name specifications. + +"------- SORT ------ +"Named data object specified within parenteses +DATA(field_name) = 'COL1'. +SORT itab_ek BY (field_name) DESCENDING. +"Unnamed data object specified within parenteses +SORT itab_ek BY ('COL2') ASCENDING. + +"------- READ TABLE ------ +"Reading by specifying keys dynamically +"Implicitly specifying the table key values in a work area (USING KEY addition) +DATA(wa_read) = VALUE demo_struct( col2 = `aaa` ). +READ TABLE itab FROM wa_read USING KEY ('SK') REFERENCE INTO DATA(read_ref). + +"Explicitly specifying the key and key values (TABLE KEY addition) +"The component names can also be specified dynamically (which is done in most of the +"following examples for demonstration purposes). Note that each component of the table +"key must be specified. +READ TABLE itab WITH TABLE KEY ('SK') COMPONENTS ('COL2') = `aaa` REFERENCE INTO read_ref. +"Specifying the predefined name primary_key explicitly and dynamically +READ TABLE itab WITH TABLE KEY ('PRIMARY_KEY') COMPONENTS ('COL1') = 1 REFERENCE INTO read_ref. +"If the addition COMPONENTS is not specified, the primary table key is implicitly used. +READ TABLE itab WITH TABLE KEY ('COL1') = 1 REFERENCE INTO read_ref. + +"Reading using a free key (WITH KEY addition) +READ TABLE itab WITH KEY ('COL3') = `yyy` REFERENCE INTO read_ref. +"The addition can also be used by specifying a secondary table key name +READ TABLE itab WITH KEY ('SK') COMPONENTS ('COL2') = `ccc` REFERENCE INTO read_ref. + +"Reading based on a table index (INDEX addition) +"Not using the addition USING KEY means reading from the primary table index. +READ TABLE itab INDEX 1 USING KEY ('SK') REFERENCE INTO read_ref. + +"More dynamic specification options when specifying the target as work area +"(COMPARING/TRANSPORTING additions) +"TRANSPORTING: Specifying which components shall be respected +READ TABLE itab INDEX 1 INTO DATA(workarea) TRANSPORTING ('COL1') ('COL3'). + +"COMPARING: If the content of the compared components is identical, sy-subrc is set +"to 0, and otherwise to 2. The line found is assigned to the work area independently +"of the result of the comparison. +workarea-('COL3') = `uvw`. +READ TABLE itab INDEX 1 INTO workarea COMPARING ('COL3') TRANSPORTING ('COL1') ('COL3'). +IF sy-subrc <> 0. + ... +ENDIF. + +"------- Table expressions ------ +"Similar to READ TABLE statements, you can specify table lines with 3 alternatives: +"index read, read using free key, table key +"Also there, dynamic specifications are possible regarding the key specifications. + +"Reading based on index with dynamic key specifications +"Specifying the secondary table index of a sorted secondary key +DATA(wa_te1) = itab[ KEY ('SK') INDEX 1 ]. +"Reading using a free key, the keys are specified dynamically +DATA(wa_te2) = itab[ ('COL2') = `bbb` ('COL3') = `yyy` ]. + +"Reading using a table key +"Specyfing the table key explicitly +"Note: Unlike READ TABLE statements, the name of the table key must be specified. The +"addition COMPONENTS can be omitted. +"In the following example, the component names are also specified dynamically. +DATA(wa_te3) = itab[ KEY ('SK') ('COL2') = `ccc` ]. +"Specifying the COMPONENTS addition explicitly +DATA(wa_te4) = itab[ KEY ('PRIMARY_KEY') COMPONENTS ('COL1') = 1 ]. + +"Accessing components +"As shown above, chaininings with the (object) component selector are possible. +"The examples use index access and write positions. +itab[ 1 ]-('COL2') = `jkl`. +itab_ref[ 1 ]->('COL2') = `mno`. + +"------- LOOP AT ------ +"USING KEY addition: Overriding the standard order determined by the table category +LOOP AT itab REFERENCE INTO DATA(ref) USING KEY ('SK'). + ... +ENDLOOP. + +"When the primary table key is specified, the loop behaves as if it was not specified. +"So, the following statement corresponds to the one below. +LOOP AT itab REFERENCE INTO ref USING KEY ('PRIMARY_KEY'). + ... +ENDLOOP. + +LOOP AT itab REFERENCE INTO ref. + ... +ENDLOOP. + +"Dynamic WHERE condition +"You can specify a character-like data object or a standard table with character-like +"line type. +DATA(cond_loop) = `COL1 > 1`. +LOOP AT itab REFERENCE INTO ref WHERE (cond_loop). + ... +ENDLOOP. + +"------- INSERT ------ +"The USING KEY addition (which accepts a dynamic specification) affects the order in which lines are inserted. + +"Result of the following example when using the ... +"- secondary table key: order of itab entries 5 ... /4 ... /... +"- primary table key: order of itab entries 4 ... /5 ... /... +INSERT LINES OF VALUE itab_type( ( col1 = 4 col2 = `eee` col3 = `www` ) + ( col1 = 5 col2 = `ddd` col3 = `vvv` ) ) + USING KEY ('SK') + "USING KEY ('PRIMARY_KEY') + INTO itab INDEX 1. + +"Excursion: Using LOOP AT statements with the USING KEY addition +"and exploring the table index +"Declaring demo tables to hold the internal table entries +DATA it_seckey_idx TYPE TABLE OF demo_struct WITH EMPTY KEY. +DATA it_primekey_idx LIKE it_seckey_idx. + +"Visualizing the secondary table index +LOOP AT itab INTO DATA(wa_sk) USING KEY ('SK'). + APPEND wa_sk TO it_seckey_idx. +ENDLOOP. + +"Visualizing the primary table index +LOOP AT itab INTO DATA(wa_pk) USING KEY ('PRIMARY_KEY'). + APPEND wa_pk TO it_primekey_idx. +ENDLOOP. + +"------- MODIFY ------ +"In the following example, a line is modified based on a work area and a table key. +"The component col1 is left out from the work area intentionally. +"If the primary table key was used, the value of sy-subrc would be 4, and no modification was done. +"The optional addition transporting is specified to denote what should be modified. In this example, +"the component is also specified dynamically. +MODIFY TABLE itab FROM VALUE #( col2 = `bbb` col3 = `uuu` ) USING KEY ('SK') TRANSPORTING ('COL3'). + +"In the following example, a line is modified based on a work area, an index specification and a +"table key. +"INDEX can also be positioned after FROM. +MODIFY itab INDEX 2 USING KEY ('SK') FROM VALUE #( col3 = `ttt` ) TRANSPORTING ('COL3'). + +"Dynamic WHERE clause (only to be used with the TRANSPORTING addition) +"The USING KEY addition is also possible. Check the ABAP Keyword Documentation +"for special rules that apply. +DATA(cond_mod) = `COL1 < 3`. +MODIFY itab FROM VALUE #( col3 = `sss` ) TRANSPORTING ('COL3') WHERE (cond_mod). + +"------- DELETE ------ +"A single line or multipled lines can be deleted. +"Note that DELETE ADJACENT DUPLICATES statements can also be specified using +"dynamic parts. + +"Deleting based on a dynamically specified table key +"The values can be declared either implicitly in a work area after FROM or explicitly +"by listing the components of the table key after TABLE KEY. +"If the USING KEY addition is not specified, the primary table key is used by default. +DELETE TABLE itab FROM VALUE #( col2 = `eee` col3 = `www` ) USING KEY ('SK'). + +"Each component of the table key must be listed. +DELETE TABLE itab WITH TABLE KEY ('SK') COMPONENTS ('COL2') = `ddd`. + +"Deleting based on the table index +DELETE itab INDEX 1 USING KEY ('SK'). + +"Deleting multiple lines and specifying the WHERE conditions dynamically +"The USING KEY addition is also possible. +DATA(condition_tab) = VALUE string_table( ( `COL1 < 3` ) + ( `OR` ) + ( `COL3 = ``www``` ) ). +DELETE itab WHERE (condition_tab). +``` + +

⬆️ back to top

+ +### Dynamic ABAP SQL Statements + +```abap +"Dynamic SELECT list +DATA(select_list) = `CARRID, CONNID, FLDATE`. +DATA fli_tab TYPE TABLE OF zdemo_abap_fli WITH EMPTY KEY. + +SELECT (select_list) + FROM zdemo_abap_fli + INTO CORRESPONDING FIELDS OF TABLE @fli_tab. + +"Dynamic FROM clause +DATA(table) = 'ZDEMO_ABAP_FLI'. +SELECT * + FROM (table) + INTO TABLE @fli_tab. + +"Excursion: Compatible target data objects +"In the examples above, the data object/type is created statically. + +"Creating an anonymous data object with a CREATE DATA statement +"and specifiying the type dynamically. +"You can use the dereferenced object reference variable as target. +DATA itab_dyn TYPE REF TO data. +CREATE DATA itab_dyn TYPE TABLE OF (table). + +SELECT * + FROM (table) + INTO TABLE @itab_dyn->*. + +"In older ABAP code, you may find assignments to a field symbol +"due to the reasons mentioned above. +FIELD-SYMBOLS TYPE ANY TABLE. +ASSIGN itab_dyn->* TO . + +SELECT * + FROM (table) + INTO TABLE @. + +"Similar to the NEW operator, you can use the addition NEW +"to create an anonymous data object in place. The advantage is +"that the data type is constructed in a suitable way. +SELECT * + FROM (table) + INTO TABLE NEW @DATA(dref_tab). + +"Dynamic WHERE clause +"The example includes a WHERE clause that is created as an internal +"table with a character-like row type. +DATA(where_clause) = VALUE string_table( ( `CARRID = 'LH'` ) + ( `OR` ) + ( `CARRID = 'AA'` ) ). + +SELECT * + FROM zdemo_abap_fli + WHERE (where_clause) + INTO TABLE NEW @DATA(tab_dyn_where). + +"Dynamic ORDER BY clause +SELECT * + FROM zdemo_abap_fli + ORDER BY (`FLDATE`) + INTO TABLE NEW @DATA(tab_dyn_order). + +"SELECT statement with miscellaneous dynamic specifications +SELECT (`CARRID, CONNID, FLDATE`) + FROM (`ZDEMO_ABAP_FLI`) + WHERE (`CARRID <> ``AA```) + ORDER BY (`FLDATE`) + INTO TABLE NEW @DATA(tab_dyn_misc). + +"Further dynamic specifications in other ABAP SQL statements +"Creating a structure to be inserted into the database table +SELECT SINGLE * + FROM (table) + INTO NEW @DATA(dref_struc). +dref_struc->('CARRID') = 'YZ'. + +INSERT (table) FROM @dref_struc->*. + +dref_struc->('CURRENCY') = 'EUR'. +UPDATE (table) FROM @dref_struc->*. + +dref_struc->('SEATSOCC') = 10. +MODIFY (table) FROM @dref_struc->*. + +DELETE FROM (table) WHERE (`CARRID = 'YZ'`). +``` + +

⬆️ back to top

+ +**Excursion**: To take up the use case mentioned in the introduction about retrieving the content of a database table, storing it in an internal table, and +displaying it when the database table name is specified dynamically at +runtime, see the following code snippet. Note the comments. + + +```abap +CLASS zcl_example_class DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. +CLASS zcl_example_class IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + "The example retrieves the content of a database table, storing it in an + "internal table, and displaying it when the database table name is + "specified dynamically at runtime. + "Certainly, there are quite some ways to achieve it, and that work out + "of the box. For example, in ABAP for Cloud Development, you can implement + "the classrun if_oo_adt_classrun and output content using the out->write(...) + "method. You can also inherit from cl_demo_classrun in your class. In + "classic ABAP, you can, for example and additionally, use cl_demo_output or + "ALV. + "Notes: + "- The following example is just ABAP code exploring dynamic programming + " aspects. Note the disclaimer in the README of the cheat sheet repository. + " It is an example that sets its focus on a dynamic SELECT statement and + " processing internal table content by dynamically accessing structure + " components. + "- The ways mentioned above are way more powerful (e.g. in most cases also + " nested and deep data objects can be displayed for demo purposes). + "- For simplicity, column contents are converted to string here if necessary, + " i.e. all column contents must be convertible to string. + "- For display purposes, the snippet uses the classrun methods to display + " results sequentially - instead of displaying the internal table + " content retrieved by the SELECT statement directly. + "- The example uses database tables from the cheat sheet repository. To fill + " them, you can use the method call zcl_demo_abap_aux=>fill_dbtabs( ).. + zcl_demo_abap_aux=>fill_dbtabs( ). + + "Data objects and types relevant for the example (length and offset for + "content display) + DATA str TYPE string. + TYPES: BEGIN OF comp_struc, + name TYPE string, + len TYPE i, + off TYPE i, + END OF comp_struc. + DATA it_comps TYPE TABLE OF comp_struc WITH EMPTY KEY. + + "Database table of type string containing names of database tables; + "table is looped over to output content of all database tables + DATA(dbtabs) = VALUE string_table( ( `ZDEMO_ABAP_CARR` ) + ( `ZDEMO_ABAP_FLI` ) + ( `ZDEMO_ABAP_FLSCH` ) ). + + LOOP AT dbtabs INTO DATA(dbtab). + "Retrieving database content of a dynamically specified database table + TRY. + SELECT * + FROM (dbtab) + INTO TABLE NEW @DATA(itab) + UP TO 5 ROWS. + CATCH cx_sy_dynamic_osql_semantics INTO DATA(sql_error). + CLEAR itab->*. + out->write( |Table { dbtab } does not exist.| ). + ENDTRY. + + IF sql_error IS INITIAL. + "Getting table component names using RTTI methods + TRY. + DATA(type_descr_obj_tab) = CAST cl_abap_tabledescr( + cl_abap_typedescr=>describe_by_data( itab->* ) ). + DATA(tab_comps) = CAST cl_abap_structdescr( + type_descr_obj_tab->get_table_line_type( ) )->get_components( ). + LOOP AT tab_comps ASSIGNING FIELD-SYMBOL(). + APPEND VALUE #( name = -name len = strlen( -name ) ) TO it_comps. + ENDLOOP. + CATCH cx_sy_move_cast_error INTO DATA(error). + out->write( |{ error->get_text( ) }| ). + ENDTRY. + + IF error IS INITIAL. + out->write( |\n| ). + out->write( |Retrieved content of database table { dbtab }:| ). + "Implementation for properly aligning the content + "The example is implemented to check the length of the column names as well as the + "length of the values in the columns. It determines the length of the longest string + "in each column. Depending on the length values, either the length of the column name + "or the length of the longest string in a column is stored in an internal table that + "contains information for calculating the offset. + LOOP AT tab_comps ASSIGNING FIELD-SYMBOL(). + ASSIGN it_comps[ name = -name ] TO FIELD-SYMBOL(). + DATA(max_content) = REDUCE i( INIT len = -len + FOR IN itab->* + NEXT len = COND #( WHEN strlen( CONV string( -(-name) ) ) > len + THEN strlen( CONV string( -(-name) ) ) + ELSE len ) ). + "Extend the length value to leave some more space + IF max_content > -len. + -len = max_content + 3. + ELSE. + -len += 3. + ENDIF. + ENDLOOP. + "Calculating offset values + DATA max_str_len TYPE i. + LOOP AT it_comps ASSIGNING FIELD-SYMBOL(). + DATA(tabix) = sy-tabix. + READ TABLE it_comps INDEX tabix - 1 ASSIGNING FIELD-SYMBOL(). + -off = COND #( WHEN tabix = 1 THEN 0 ELSE -len + -off ). + max_str_len += -len. + ENDLOOP. + "Providing enough space so that table row content can be inserted based on + "the offset specification + SHIFT str BY max_str_len PLACES RIGHT. + "Adding the column names first + LOOP AT it_comps ASSIGNING FIELD-SYMBOL(
). + str = insert( val = str sub =
-name off =
-off ). + ENDLOOP. + out->write( str ). + "Processing all lines in the internal table containing the retrieved table rows + LOOP AT itab->* ASSIGNING FIELD-SYMBOL(). + CLEAR str. + SHIFT str BY max_str_len PLACES RIGHT. + DO. + TRY. + str = insert( val = str sub = -(sy-index) off = it_comps[ sy-index ]-off ). + CATCH cx_sy_assign_illegal_component cx_sy_range_out_of_bounds cx_sy_itab_line_not_found. + EXIT. + ENDTRY. + ENDDO. + out->write( str ). + ENDLOOP. + ENDIF. + out->write( |\n| ). + CLEAR: str, it_comps. + ENDIF. + ENDLOOP. + ENDMETHOD. +ENDCLASS. +``` + +

⬆️ back to top

+ +### Dynamic Invoke +The following code snippet shows dynamically specifying [procedure](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") calls. + +``` abap +"Note: Dynamic method calls require a CALL METHOD statement. +"The following examples assume that there are no mandatory +"parameters defined for the method. +"Possible for methods of the same class, works like me->(meth) +CALL METHOD (meth). +"Class specified statically +CALL METHOD class=>(meth). +"Object reference variable specified statically; +"also possible for interface reference variables +CALL METHOD oref->(meth). + +"The following statements are possible for all visible static methods +"Class dynamically specified +CALL METHOD (class)=>meth. +"Class and method dynamically specified +CALL METHOD (class)=>(meth). + +"The following examples assume that there are parameters defined +"for the method. +"Assigning actual parameters to the formal parameters statically +CALL METHOD class=>(meth) EXPORTING p1 = a1 p2 = a2 ... + IMPORTING p1 = a1 p2 = a2 ... + +"Assigning actual parameters to the formal parameters dynamically +DATA ptab TYPE abap_parmbind_tab. +ptab = ... + +CALL METHOD class=>(meth) PARAMETER-TABLE ptab. + +"Notes on PARAMETER-TABLE ptab +"- The table (of type abap_parmbind_tab; line type is abap_parmbind) +" must be filled and have a line for all non-optional parameters. +"- Components: name -> formal parameter name +" kind -> kind of parameter, e. g. importing +" value -> pointer to appropriate actual parameter, +" is of type REF TO data +"The addition EXCEPTION-TABLE for exceptions is not dealt with here. + +"Example that uses the PARAMETER-TABLE addition +"Creating an instance by specifying the type statically +"An example class of the cheat sheet repository is used. +DATA(oref1) = NEW zcl_demo_abap_objects( ). +"Calling an instance method +"The method multiplies an integer by 3. +"The calculation result is returned. +DATA(result) = oref1->triple( i_op = 2 ). "6 + +"Dynamic equivalent +"Creating an instance of a class by specifying the type +"dynamically +DATA oref2 TYPE REF TO object. +CREATE OBJECT oref2 TYPE ('ZCL_DEMO_ABAP_OBJECTS'). + +"Creating parameter table +DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'I_OP' + kind = cl_abap_objectdescr=>exporting + value = NEW i( 3 ) ) + ( name = 'R_TRIPLE' + kind = cl_abap_objectdescr=>returning + value = NEW i( ) ) ). + +"Dynamic method call and specifying a parameter table +CALL METHOD oref2->('TRIPLE') PARAMETER-TABLE ptab. +result = ptab[ name = 'R_TRIPLE' ]-('VALUE')->*. "9 +``` + +

⬆️ back to top

+ +### Validating Input for Dynamic Specifications (CL_ABAP_DYN_PRG) + +You can use the `CL_ABAP_DYN_PRG` class to validate input for dynamic specifications. +There are several methods for different use cases. See the class documentation (click F2 on the class name in ADT) for more information. +The following examples show some of those methods. If the validation is successful, the methods in the examples return the input value. +Otherwise, an exception is raised. + +```abap +"The following method checks database table names. The name is provided +"with the val parameter. The packages formal parameter expects a table +"containing the names of packages in which the specified table should be +"included. Assuming you provide incorrect input for the table name, or +"the table is not contained in the specified packages, you can expect an +"exception to be raied. + +TRY. + DATA(dbtab) = cl_abap_dyn_prg=>check_table_name_tab( + val = `ZDEMO_ABAP_FLI` + packages = VALUE #( ( `TEST_ABAP_CHEAT_SHEETS` ) + ( `TEST_SOME_PACK` ) ) ). + + SELECT SINGLE * FROM (dbtab) INTO NEW @DATA(ref_wa). + CATCH cx_abap_not_a_table cx_abap_not_in_package. + ... +ENDTRY. + +"In the following examples, a method is used to check whether +"the input is allowed or not. For this, you specify an allowlist. +"Here, the relvant parameter expects a comma-separated list of +"allowed values. +TRY. + DATA(value1) = cl_abap_dyn_prg=>check_allowlist( + val = `A` + allowlist_str = `A,B,C,D` ). + + ... "Here might go an ABAP SQL statement with a dynamic specification. + CATCH cx_abap_not_in_allowlist. + ... +ENDTRY. + +"Another parameter of the method expects an internal table that +"contains the allowed values. +TRY. + DATA(value2) = cl_abap_dyn_prg=>check_allowlist( + val = `XYZ` + allowlist_htab = VALUE #( ( `A` ) + ( `B` ) + ( `C` ) + ( `D` ) ) ). + + ... "Here might go an ABAP SQL statement with a dynamic specification. + CATCH cx_abap_not_in_allowlist. + ... +ENDTRY. +``` + +

⬆️ back to top

+ +## Runtime Type Services (RTTS) + +[RTTS](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_services_glosry.htm "Glossary Entry") +represent a hierarchy of [type description classes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentype_class_glosry.htm "Glossary Entry") +containing methods for +- getting type information on data objects, data types or + [instances](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninstance_glosry.htm "Glossary Entry") + at runtime ([Runtime Type Identification (RTTI)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm "Glossary Entry")). +- defining and creating new data types as [type description objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentype_object_glosry.htm) at runtime ([Runtime Type Creation (RTTC)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_creation_glosry.htm "Glossary Entry")). + +The hierarchy of type description classes is as follows. + +
+CL_ABAP_TYPEDESCR
+  |
+  |--CL_ABAP_DATADESCR
+  |   |
+  |   |--CL_ABAP_ELEMDESCR
+  |   |   |
+  |   |   |--CL_ABAP_ENUMDESCR
+  |   |
+  |   |--CL_ABAP_REFDESCR
+  |   |--CL_ABAP_COMPLEXDESCR
+  |       |
+  |       |--CL_ABAP_STRUCTDESCR
+  |       |--CL_ABAP_TABLEDESCR
+  |
+  |--CL_ABAP_OBJECTDESCR
+     |
+     |--CL_ABAP_CLASSDESCR
+     |--CL_ABAP_INTFDESCR
+
+So, the +[superclass](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensuperclass_glosry.htm "Glossary Entry") +`CL_ABAP_TYPEDESCR` has multiple +[subclasses](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensubclass_glosry.htm "Glossary Entry"), +for example, to deal with each kind of type. +Working with this inheritance tree means making use of +[casts](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abencast_glosry.htm "Glossary Entry"), +especially +[downcasts](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendown_cast_glosry.htm "Glossary Entry") when retrieving information at runtime. +Detailing out all the possibilities for the information retrieval and +type creation is beyond scope. Check the information, options and +various methods that can be used in the class documentation, e. g. using +F2 help information in +[ADT](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenadt_glosry.htm "Glossary Entry"), +for more details. + +

⬆️ back to top

+ +### Getting Type Information at Runtime + +With RTTI, you can determine data types at runtime using description methods in type description classes. +To get the type information, you can get a reference to a type description object of a type, that is, an instance of a type description class. +The type properties are represented by attributes that are accessible through the type description object. + + +> **💡 Note**
+> - For each type, there is exactly one type description object. +> - For each type category (elementary type, table, and so on), there is a type description class (e.g. `CL_ABAP_STRUCTDESCR` for structures, as shown in the hierarchy tree above) that has special attributes (i.e. the properties of the respective types). +> - References to type description objects can be used, for example, after the `TYPE HANDLE` addition of the `CREATE DATA` and `ASSIGN` statements. + +The following examples show the retrieval of type information. Instead of the extra declaration of data reference variables, you can use +[inline declarations](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninline_declaration_glosry.htm "Glossary Entry"). +[Method chaining](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenmethod_chaining_glosry.htm "Glossary Entry") +comes in handy, too. + +```abap +"------------------------------------------------------------------------ +"---------------- Getting general type information ---------------------- +"------------------------------------------------------------------------ + +"Getting references to type description objects of a type ... + +"... using the cl_abap_typedescr=>describe_by_name method. +"In this case, the name of the types are used. +"The following examples cover elementary, structured and +"internal table types. +TYPES elemtype TYPE n LENGTH 3. +TYPES structype TYPE zdemo_abap_carr. +TYPES strtabtype TYPE string_table. + +"The reference in the type description object references an +"object from one of the classes CL_ABAP_ELEMDESCR, CL_ABAP_ENUMDESCR, +"CL_ABAP_REFDESCR, CL_ABAP_STRUCTDESCR, CL_ABAP_TABLEDESCR, +"CL_ABAP_CLASSDESCR, or CL_ABAP_INTFDESCR. You may want to check the +"content of the type description objects in the debugger. +DATA(tdo_by_name_elem) = cl_abap_typedescr=>describe_by_name( 'ELEMTYPE' ). +DATA(tdo_by_name_struc) = cl_abap_typedescr=>describe_by_name( 'STRUCTYPE' ). +DATA(tdo_by_name_itab) = cl_abap_typedescr=>describe_by_name( 'STRTABTYPE' ). + +"Inline declarations are handy to avoid helper variables such as +"in the following example. +DATA tdo_by_name_elem_helper TYPE REF TO cl_abap_typedescr. +tdo_by_name_elem_helper = cl_abap_typedescr=>describe_by_name( 'ELEMTYPE' ). + +"... using the cl_abap_typedescr=>describe_by_data method. +"In this case, the data objects are provided. +"The examples cover an elementary data object, a structure and and +"internal table. +DATA elemdobj TYPE elemtype. +DATA strucdobj TYPE structype. +DATA tabledobj TYPE strtabtype. + +DATA(tdo_by_data_elem) = cl_abap_typedescr=>describe_by_data( 'ELEMTYPE' ). +DATA(tdo_by_data_struc) = cl_abap_typedescr=>describe_by_data( 'STRUCTYPE' ). +DATA(tdo_by_data_itab) = cl_abap_typedescr=>describe_by_data( 'STRTABTYPE' ). + +"... using the cl_abap_typedescr=>describe_by_data_ref method +"In this case, a data reference variable is used. +"Note: As a result, the method returns a reference that points to +"an object in one of the classes CL_ABAP_ELEMDESCR, CL_ABAP_ENUMDESCR, +"CL_ABAP_REFDESCR, CL_ABAP_STRUCTDESCR, or CL_ABAP_TABLEDSECR. + +DATA dref1 TYPE REF TO i. +dref1 = NEW #( ). +"Data reference pointing to CL_ABAP_ELEMDESCR +DATA(tdo_by_dref1) = cl_abap_typedescr=>describe_by_data_ref( dref1 ). +"Data reference pointing to CL_ABAP_TABLEDSECR +DATA(dref2) = NEW string_table( ). +DATA(tdo_by_dref2) = cl_abap_typedescr=>describe_by_data_ref( dref2 ). + +"... using the cl_abap_typedescr=>describe_by_object_ref method +"In this case, an object reference variable is used. +DATA oref TYPE REF TO zcl_demo_abap_objects. +oref = NEW #( ). +DATA(tdo_by_oref) = cl_abap_typedescr=>describe_by_object_ref( oref ). + +"------------------------------------------------------------------------ +"--- Getting more detailed information by programmatically accessing ---- +"--- the attributes ----------------------------------------------------- +"------------------------------------------------------------------------ + +"------------------------------------------------------------------------ +"--- Examples using a type description object for an elementary type ---- +"------------------------------------------------------------------------ +DATA(elem_kind) = tdo_by_name_elem->kind. "E (elementary) +DATA(elem_absolute_name) = tdo_by_name_elem->absolute_name. "Check in the debugger for such a local type +DATA(elem_relative_name) = tdo_by_name_elem->get_relative_name( ). "ELEMTYPE +DATA(elem_is_ddic_type) = tdo_by_name_elem->is_ddic_type( ). "has the value abap_false + +"Getting more information using type-specific type description classes (e.g. cl_abap_elemdescr for elementary +"types, as shown in the hierarchy tree above) +"Using casts, you can access special attributes (i.e. the properties of the respective types). + +"Creating a data reference variable to hold the reference to +"the type description object +DATA ref_elemdescr TYPE REF TO cl_abap_elemdescr. +ref_elemdescr = CAST #( tdo_by_name_elem ). +"Using the older cast operator ?= (which is not used in the examples) +ref_elemdescr ?= tdo_by_name_elem. + +"Alternatives using inline declaration +DATA(ref_elemdescr2) = CAST cl_abap_elemdescr( tdo_by_name_elem ). +"Using method chaining, you can omit extra declarations +DATA(ref_elemdescr3) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_name( 'ELEMTYPE' ) ). +DATA(elem_abs_name) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_name( 'ELEMTYPE' ) )->absolute_name. +"Implementing a check before the cast to the type-specific type description class +IF tdo_by_name_elem IS INSTANCE OF cl_abap_elemdescr. + DATA(ref_elemdescr4) = CAST cl_abap_elemdescr( tdo_by_name_elem ). +ENDIF. + +"Some examples for more detailed information that is accessible after +"the cast. Check the options after the object component selector ->. +DATA(elem_output_length) = ref_elemdescr->output_length. "3 +"The following method checks compatibility of a specified data object +DATA(elem_applies1) = ref_elemdescr->applies_to_data( elemdobj ). "has the value abap_true +DATA test_dobj TYPE c LENGTH 3. +DATA(elem_applies2) = ref_elemdescr->applies_to_data( test_dobj ). "has the value abap_false + +"----------------------------------------------------------------- +"--- Examples using a type description object for a structure ---- +"----------------------------------------------------------------- +DATA ref_structdescr1 TYPE REF TO cl_abap_structdescr. +ref_structdescr1 = CAST #( tdo_by_name_struc ). + +"Check examples before making the cast +"The examples also use inline declaration. +CASE TYPE OF tdo_by_name_struc. + WHEN TYPE cl_abap_structdescr. + DATA(ref_structdescr2) = CAST cl_abap_structdescr( tdo_by_name_struc ). + WHEN OTHERS. + ... +ENDCASE. + +DATA(ref_structdescr3) = COND #( WHEN tdo_by_name_struc IS INSTANCE OF cl_abap_structdescr + THEN CAST cl_abap_structdescr( tdo_by_name_struc ) ). + +"More details accessible after the cast +DATA(struc_kind) = ref_structdescr1->struct_kind. "F (flat) +"The following attribute returns a table with component information, such as +"the component names and type kinds. +DATA(struc_components) = ref_structdescr1->components. +"The following method also returns a table with component information. In this case, +"more information is returned such as type description objects of each component and more. +DATA(struc_components_tab) = ref_structdescr1->get_components( ). + +"----------------------------------------------------------------------- +"--- Examples using a type description object for an internal table ---- +"----------------------------------------------------------------------- +DATA ref_tabledescr1 TYPE REF TO cl_abap_tabledescr. +ref_tabledescr1 = CAST #( tdo_by_name_itab ). +"Cast with inline declaration +DATA(ref_tabledescr2) = CAST cl_abap_tabledescr( tdo_by_name_itab ). + +"Another internal table as an example +DATA itab TYPE SORTED TABLE OF zdemo_abap_carr WITH UNIQUE KEY carrid. +DATA(ref_tabledescr3) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( itab ) ). + +DATA(itab_table_kind) = ref_tabledescr3->table_kind. "O (sorted table) +DATA(itab_has_unique_key) = ref_tabledescr3->has_unique_key. "has the value abap_true +"Returns a table with the names of internal table keys +DATA(itab_table_key) = ref_tabledescr3->key. "carrid +"Returns a table with a description of all table keys, e.g. +"all components of a key, key kind (U, unique, in the example case), +"information whether the key is the primary key etc. +DATA(itab_keys) = ref_tabledescr3->get_keys( ). +"If you want to get information about the line type, e.g. finding out about +"the component names, another cast is required. +"First, getting a reference to the type description object for the structured type. +DATA(itab_line_type) = ref_tabledescr3->get_table_line_type( ). +"Then, performing a cast to access the component information as shown above. +DATA(itab_line_info) = CAST cl_abap_structdescr( itab_line_type ). +DATA(itab_comps1) = itab_line_info->components. +DATA(itab_comps2) = itab_line_info->get_components( ). + +"---------------------------------------------------------------------- +"--- Examples using a type description object for a data reference ---- +"---------------------------------------------------------------------- +DATA ref_refdescr1 TYPE REF TO cl_abap_refdescr. +TYPES type_ref_i TYPE REF TO i. +DATA(tdo_ref) = cl_abap_typedescr=>describe_by_name( 'TYPE_REF_I' ). +ref_refdescr1 = CAST #( tdo_ref ). +DATA(ref_refdescr2) = CAST cl_abap_refdescr( tdo_ref ). + +"Getting a reference to the type description object of a type used to +"type the reference +DATA(ref_type) = ref_refdescr1->get_referenced_type( ). +DATA(ref_abs_name) = ref_refdescr1->get_referenced_type( )->absolute_name. "\TYPE=I + +"------------------------------------------------------------------------- +"--- Examples using a type description object for an object reference ---- +"------------------------------------------------------------------------- +DATA ref_oref1 TYPE REF TO cl_abap_objectdescr. +ref_oref1 = CAST #( tdo_by_oref ). +"See the hierarchy of type description classes. You may also use +"cl_abap_classdescr. +DATA(ref_oref2) = CAST cl_abap_classdescr( tdo_by_oref ). + +"Returns a table with information about the class attributes +DATA(class_attributes) = ref_oref1->attributes. + +"Returns a table with information about the methods such as +"parameters, visibility and more +DATA(class_methods) = ref_oref1->methods. + +"Returns a table with information about the interfaces implemented +DATA(class_intf) = ref_oref1->interfaces. + +"Can class be instantiated +DATA(class_is_inst) = ref_oref1->is_instantiatable( ). "has the value abap_true + +"Using an interface +DATA(tdo_intf) = cl_abap_typedescr=>describe_by_name( 'ZDEMO_ABAP_OBJECTS_INTERFACE' ). +DATA ref_iref TYPE REF TO cl_abap_intfdescr. +ref_iref = CAST #( tdo_intf ). "cl_abap_objectdescr is also possible + +DATA(ref_intf_attr) = ref_iref->attributes. +DATA(ref_intf_meth) = ref_iref->methods. +DATA(ref_intf_attr_objdescr) = CAST cl_abap_objectdescr( tdo_intf )->attributes. +``` + +Excursions: + +```abap +"Casting and method chaining as above in contrast to the following +"extra declarations. If the variables were not declared inline as +"in the example, there would be even more lines of code. +DATA(a) = cl_abap_typedescr=>describe_by_data( some_struc ). +DATA(b) = CAST cl_abap_structdescr( a ). +DATA(c) = b->components. + +"get_included_view method: Getting type information for included +"components, e.g. in case of deep structures +TYPES: BEGIN OF st, + a TYPE i, "elementary type + b TYPE zdemo_abap_carr, "structure + c TYPE string_table, "internal table + END OF st. + +DATA(type_descr) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( 'ST' ) )->get_included_view( ). + +"As mentioned earlier about type name specifications for statements +"such as CREATE DATA, in addition to character-like data objects for +"the type name specified in the parentheses, you can also use absolute +"type names. + +"Type to refer to +TYPES type4abs TYPE p LENGTH 4 DECIMALS 3. + +"Data and object reference variables with generic types +DATA dref4abs TYPE REF TO data. +DATA oref4abs TYPE REF TO object. + +"Getting absolute names +DATA(abs_name_type) = cl_abap_typedescr=>describe_by_name( + 'TYPE4ABS' )->absolute_name. +DATA(abs_name_cl) = cl_abap_typedescr=>describe_by_name( + 'ZCL_DEMO_ABAP_DYNAMIC_PROG' )->absolute_name. + +"Data references +"Named data object holding the absolute name +CREATE DATA dref4abs TYPE (abs_name_type). + +"Unnamed data object +CREATE DATA dref4abs TYPE ('\TYPE=STRING'). + +"Object references +"Named data object +CREATE OBJECT oref4abs TYPE (abs_name_cl). + +"Unnamed data object +CREATE OBJECT oref4abs TYPE ('\CLASS=ZCL_DEMO_ABAP_DYNAMIC_PROG'). +``` + +

⬆️ back to top

+ +### Dynamically Creating Data Types at Runtime +You can create data types at program runtime using methods of the type description classes of RTTS. +These types are only valid locally in the program. They are also anonymous, i.e. they are only accessible through type description objects. +As shown above, you can get a reference to a type description object of a type using the static methods of the class `CL_ABAP_TYPEDESCR`. +```abap +"For example, a structured type +DATA(type_descr_obj) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( 'SOME_STRUC_TYPE' ) ). +``` + +The focus here is on using RTTC methods such as `get...`. It is recommended that you use the `get` method instead of the `create` method. + +```abap +"---------------------------------------------------------------------- +"--- Creating type description objects using elementary data types ---- +"---------------------------------------------------------------------- +"Conceptually, all elementary, built-in ABAP types already +"exist and can be accessed by the corresponding get_* methods. +"In ADT, click CTRL + space after cl_abap_elemdescr=>... +"to check out the options. The following examples show a +"selection. + +DATA(tdo_elem_i) = cl_abap_elemdescr=>get_i( ). +DATA(tdo_elem_string) = cl_abap_elemdescr=>get_string( ). + +"For the length specification of type c and others, there is +"an importing parameter available. +DATA(tdo_elem_c_l20) = cl_abap_elemdescr=>get_c( 20 ). + +"Type p with two parameters to be specified. +DATA(tdo_elem_p) = cl_abap_elemdescr=>get_p( p_length = 3 + p_decimals = 2 ). + +"Note: Instead of calling get_i() and others having no importing +"parameters, you could also call the describe_by_name( ) method +"and pass the type names (I‚ STRING etc.) as arguments. +"DATA(tdo_elem_i_2) = CAST cl_abap_elemdescr( +" cl_abap_typedescr=>describe_by_name( 'I' ) ). +"DATA(tdo_elem_string_2) = CAST cl_abap_elemdescr( +" cl_abap_typedescr=>describe_by_name( 'STRING' ) ). + +"---------------------------------------------------------------------- +"--- Creating type description objects using structured data types ---- +"---------------------------------------------------------------------- +"They are created based on a component description table. + +"A structured type such as the following shall be created dynamically +"using a type description object. +TYPES: BEGIN OF struc_type, + a TYPE string, + b TYPE i, + c TYPE c LENGTH 5, + d TYPE p LENGTH 4 DECIMALS 3, + END OF struc_type. + +"Creating a type description object using RTTC method +"Using the get method, you can create the type description object +"dynamically based on a component table. The component table is +"of type abap_component_tab. In this example, the component table +"is created inline. +DATA(tdo_struc) = cl_abap_structdescr=>get( + VALUE #( + ( name = 'A' type = cl_abap_elemdescr=>get_string( ) ) + ( name = 'B' type = cl_abap_elemdescr=>get_i( ) ) + ( name = 'C' type = cl_abap_elemdescr=>get_c( 5 ) ) + ( name = 'D' type = cl_abap_elemdescr=>get_p( p_length = 4 + p_decimals = 3 ) ) ) ). + +"--------------------------------------------------------------------- +"--- Creating type description objects using internal table types ---- +"--------------------------------------------------------------------- +"Note: Specifying the line type is mandatory, the rest is optional. + +"An internal table type such as the following shall be created dynamically +"using a type description object. +TYPES std_tab_type_std_key TYPE STANDARD TABLE OF string WITH DEFAULT KEY. + +"Creating a type description object using RTTC method +"Not specifying the other optional parameters means that the +"default values are used, for example, standard table is the +"default value for p_table_kind. +DATA(tdo_tab_1) = cl_abap_tabledescr=>get( + p_line_type = cl_abap_elemdescr=>get_string( ) ). + +"Another internal table type for which more parameter specifications +"are needed. The following internal table type shall be created using +"a type description object. +TYPES so_table_type TYPE SORTED TABLE OF zdemo_abap_flsch WITH UNIQUE KEY carrid connid. + +"Creating a type description object using RTTC method +"The following example also demonstrates how comfortably constructor +"operators can be used at these positions. +DATA(tdo_tab_2) = cl_abap_tabledescr=>get( + p_line_type = CAST cl_abap_structdescr( + cl_abap_tabledescr=>describe_by_name( 'ZDEMO_ABAP_FLSCH' ) ) + p_table_kind = cl_abap_tabledescr=>tablekind_sorted + p_key = VALUE #( ( name = 'CARRID' ) ( name = 'CONNID' ) ) + p_unique = cl_abap_typedescr=>true ). + +" ... reference types +"Reference types such as the following shall be created using a +"type description object. +TYPES some_ref_type2t TYPE REF TO t. +TYPES some_ref_type2cl TYPE REF TO zcl_demo_abap_dynamic_prog. + +"Using RTTC methods +"You can create a reference type from a base type. This base type +"may be a class, interface or data type. +DATA(tdo_ref_1) = cl_abap_refdescr=>get( cl_abap_elemdescr=>get_t( ) ). +DATA(tdo_ref_2) = cl_abap_refdescr=>get( + cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' ) ). +"Alternative: get_by_name method +DATA(tdo_ref_3) = cl_abap_refdescr=>get_by_name( 'T' ). +DATA(tdo_ref_4) = cl_abap_refdescr=>get_by_name( 'ZCL_DEMO_ABAP_DYNAMIC_PROG' ). +``` + +

⬆️ back to top

+ +### Dynamically Creating Data Objects at Runtime + +As shown above, anonymous data objects can be dynamically created using `CREATE DATA` statements in many ways by specifying the type ... +- statically: `CREATE DATA dref TYPE string.` +- dynamically: `CREATE DATA dref TYPE (some_type).` + +Another way to dynamically create data objects with dynamic type specification is to use types created at runtime with RTTC methods. +The `CREATE DATA` statement provides the [`TYPE HANDLE`](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm) addition after which you can specify type description objects. A reference variable of the static type of class `CL_ABAP_DATADESCR` or its subclasses that points to a type description object can be specified after `TYPE HANDLE`. + +``` abap +DATA dref_cr TYPE REF TO data. + +"Elementary data object +"Type description object for an elementary type +DATA(tdo_elem_c_l20) = cl_abap_elemdescr=>get_c( 20 ). +"Creating an elementary data object based on a type description object +CREATE DATA dref_cr TYPE HANDLE tdo_elem_c_l20. + +"Structure +DATA(tdo_struc) = cl_abap_structdescr=>get( + VALUE #( + ( name = 'COMP1' type = cl_abap_elemdescr=>get_string( ) ) + ( name = 'COMP2' type = cl_abap_elemdescr=>get_i( ) ) + ( name = 'COMP3' type = cl_abap_elemdescr=>get_c( 3 ) ) ) ). + +"Creating a structure based on a type description object +CREATE DATA dref_cr TYPE HANDLE tdo_struc. + +"Internal table +"In the case below, it is a standard table with standard key by +"default because the other parameters are not specified. +DATA(tdo_tab) = cl_abap_tabledescr=>get( + p_line_type = CAST cl_abap_structdescr( + cl_abap_tabledescr=>describe_by_name( 'ZDEMO_ABAP_CARR' ) ) ). + +"Creating an internal table based on a type description object +CREATE DATA dref_cr TYPE HANDLE tdo_tab. + +"Data reference +DATA(tdo_ref) = cl_abap_refdescr=>get( cl_abap_elemdescr=>get_t( ) ). +CREATE DATA dref_cr TYPE HANDLE tdo_ref. +``` + +

⬆️ back to top

+ +## More Information +- It is recommended that you also consult section [Dynamic Programming Techniques (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abendynamic_prog_technique_gdl.htm) in the ABAP Keyword Documentation since it provides important aspects that should be considered when dealing with dynamic programming in general (e. g. security aspects or runtime error prevention). +- There are even further dynamic programming techniques in the unrestricted ABAP language scope [Standard ABAP](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenstandard_abap_glosry.htm) such as the generation or execution of programs at runtime. They are not part of this cheat sheet. Find more details on the related syntax (e. g. `GENERATE SUBROUTINE POOL`, `READ REPORT` and `INSERT REPORT` in the ABAP Keyword Documentation for Standard ABAP: [Dynamic Program Development (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_language_dynamic.htm) + +## Executable Example + +[zcl_demo_abap_dynamic_prog](./src/zcl_demo_abap_dynamic_prog.clas.abap) + +> **💡 Note**
+> - The executable example covers the following topics, among others: +> - Field symbols and data references as supporting elements for dynamic programming +> - Dynamic ABAP syntax components +> - Runtime type services (RTTS), i. e. runtime type identification (RTTI) and runtime type creation (RTTC) +> - The steps to import and run the code are outlined [here](README.md#-getting-started-with-the-examples). +> - [Disclaimer](README.md#%EF%B8%8F-disclaimer) diff --git a/README.md b/README.md index 43b0df3..d14bbeb 100644 --- a/README.md +++ b/README.md @@ -1,242 +1,243 @@ -
-
- - ABAP Keyword Documentation - - -

ABAP Cheat Sheets

- -

- Explore ABAP syntax in a nutshell & executable examples -
- -
- How to Use - · - Cheat Sheets - · - Examples -

-
-
-
-
- -[![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/abap-cheat-sheets)](https://api.reuse.software/info/github.com/SAP-samples/abap-cheat-sheets) - -ABAP cheat sheets[^1] ... -- provide a **collection of information on selected ABAP topics** in a nutshell for your reference. -- focus on **ABAP syntax**. -- include **code snippets**. -- are supported by easy-to-consume **demonstration examples** that you can import into your [SAP BTP ABAP environment](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensap_btp_abap_env_glosry.htm) (*main* branch; ABAP language version: [ABAP for Cloud Development](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_for_cloud_dev_glosry.htm)) or on-premise ABAP system ([classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm); the repository branches other than *main*) using [abapGit](https://abapgit.org/) to run and check out ABAP syntax in action in simple contexts. -- are enriched by links to glossary entries and chapters of the **ABAP Keyword Documentation** (the *F1 help*) and more for you to deep dive into the respective ABAP topics and get more comprehensive information. - -
-💡 Note -
- -- Since the ABAP cheat sheets provide information in a nutshell, they do not claim to be fully comprehensive as far as the described syntax and concepts are concerned. If you need more details, you can always consult the ABAP Keyword Documentation, for example, by choosing *F1* on a keyword in your code, or by searching directly using the online or the system-internal version. -- Unless otherwise stated in the cheat sheets, the content of this repository is relevant for these ABAP language versions (with a focus on the first): - - [ABAP for Cloud Development](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_for_sap_cloud_glosry.htm): Restricted ABAP language scope for [ABAP Cloud](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_cloud_glosry.htm) → [Online version of the documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm) - - [Standard ABAP](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenstandard_abap_glosry.htm): Unrestricted ABAP language scope, for example, for [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm) → [Online version of the documentation (latest version)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap.htm) -- Check the [Known Issues](#-known-issues) and [Disclaimer](#%EF%B8%8F-disclaimer). -- The cheat sheets provide links to glossary entries and topics in the ABAP Keyword Documentation. Note that unlike the classic ABAP-only cheat sheets, in most cases these links refer to ABAP for Cloud Development. -- [Here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrestricted_abap_elements.htm) is an overview of the different ABAP language elements in the different ABAP versions, i.e. what is allowed in ABAP Cloud and what is not. See also the released APIs [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenreleased_apis.htm). -- In order to have all ABAP cheat sheet documents in one place, the *main* branch (for ABAP Cloud examples) also contains the ABAP cheat sheet documents that are only relevant for classic ABAP. -- The example classes contained in the branches for classic ABAP mostly use syntax that is also available in ABAP for Cloud Development. Only the `TEST_ABAP_CHEAT_SHEETS_CLASSIC` subpackage contains syntax relevant to Standard ABAP and that is not available in ABAP for Cloud Development, such as dynpro-related ABAP keywords. -
- -
- -## 🏗️ How to Use - -1. **ABAP syntax info**: Get info in a nutshell on ABAP syntax and concepts related to various ABAP topics in the [ABAP cheat sheets](#-abap-cheat-sheets-overview). -2. **Demo examples**: Import the ABAP development objects of this repository (Note: *main* branch for ABAP Cloud only) into your system using [abapGit](https://abapgit.org/) as described [here](#-getting-started-with-the-examples) and run the demo classes by choosing *F9* in the [ABAP development tools for Eclipse (ADT)](https://tools.eu1.hana.ondemand.com/) for checking out the ABAP syntax in action. - -
- -## 📝 ABAP Cheat Sheets Overview - -| Cheat Sheet | Topics Covered | Demo Example | -| ------------- | ------------- | ----- | -|[ABAP for Cloud Development](19_ABAP_for_Cloud_Development.md)| Briefly outlines the terms ABAP Cloud and classic ABAP to set the context for ABAP for Cloud Development | [zcl_demo_abap_cloud_excursion](./src/zcl_demo_abap_cloud_excursion.clas.abap) (see the notes in the cheat sheet) | -|[Data Types and Data Objects](16_Data_Types_and_Objects.md)| Contains basic information about data types and data objects in ABAP | [zcl_demo_abap_dtype_dobj](./src/zcl_demo_abap_dtype_dobj.clas.abap) | -|[Internal Tables](01_Internal_Tables.md)| Creating, filling, reading from, sorting, modifying internal tables | [zcl_demo_abap_internal_tables](./src/zcl_demo_abap_internal_tables.clas.abap) | -|[Structures](02_Structures.md)| Some basics when working with structures | [zcl_demo_abap_structures](./src/zcl_demo_abap_structures.clas.abap) | -|[ABAP SQL](03_ABAP_SQL.md)| Reading from database tables using `SELECT`, changing data in database tables using `INSERT`, `UPDATE`, `MODIFY` and `DELETE` | [zcl_demo_abap_sql](./src/zcl_demo_abap_sql.clas.abap) | -|[ABAP Object Orientation](04_ABAP_Object_Orientation.md)| Working with objects and components, concepts such as inheritance, interfaces, and more | [zcl_demo_abap_objects](./src/zcl_demo_abap_objects.clas.abap) | -|[Constructor Expressions](05_Constructor_Expressions.md)| Covers constructor expressions with operators such as `VALUE`, `CORRESPONDING`, `NEW`, `CONV`, `EXACT`, `REF`, `CAST`, `COND`, `SWITCH`, `FILTER`, `REDUCE`, iteration expressions with `FOR`, `LET` expressions | [zcl_demo_abap_constructor_expr](./src/zcl_demo_abap_constructor_expr.clas.abap) | -|[Dynamic Programming](06_Dynamic_Programming.md)| Covers field symbols and data references as supporting elements for dynamic programming, dynamic ABAP syntax components, runtime type services (RTTS), i. e. runtime type identification (RTTI) and runtime type creation (RTTC) | [zcl_demo_abap_dynamic_prog](./src/zcl_demo_abap_dynamic_prog.clas.abap) | -|[String Processing](07_String_Processing.md)| Creating strings and assigning values, chaining strings, string templates, concatenating, splitting, modifying strings, searching and replacing, regular expressions | [zcl_demo_abap_string_proc](./src/zcl_demo_abap_string_proc.clas.abap) | -|[ABAP for RAP: Entity Manipulation Language (ABAP EML)](08_EML_ABAP_for_RAP.md)| Setting EML in the context of RAP, standard (create, read, update, delete) and non-standard operations (actions) |
  • [Demo RAP scenario with a managed RAP BO, external numbering (zcl_demo_abap_rap_ext_num_m)](./src/zcl_demo_abap_rap_ext_num_m.clas.abap)

  • [Demo RAP scenario with an unmanaged RAP BO, external numbering (zcl_demo_abap_rap_ext_num_u)](./src/zcl_demo_abap_rap_ext_num_u.clas.abap)

  • [Demo RAP scenario ("RAP calculator") with a managed, draft-enabled RAP BO, late numbering (zcl_demo_abap_rap_draft_ln_m)](./src/zcl_demo_abap_rap_draft_ln_m.clas.abap)
    Note that this example can also be checked out using the preview version of an SAP Fiori UI. Check the comments in the class for the steps.

  • [Demonstrating the local consumption of RAP business events in the context of a RAP demo scenario, managed RAP BO with managed internal numbering and additional save (zcl_demo_abap_rap_m_as)](./src/zcl_demo_abap_rap_m_as.clas.abap)
| -|[Excursion Down to Bits and Bytes](09_Bits_and_Bytes.md)|Covers the technical background of data types and data objects|-| -|[ABAP SQL: Working with Hierarchies](10_ABAP_SQL_Hierarchies.md)|Summarizes the functions ABAP SQL offers together with ABAP CDS for working with hierarchical data that is stored in database tables|-| -|[Internal Tables: Grouping](11_Internal_Tables_Grouping.md)|Covers the `GROUP BY` clause in statements for internal tables.|[zcl_demo_abap_sql_group_by](./src/zcl_demo_abap_sql_group_by.clas.abap)| -|[ABAP Managed Database Procedures (AMDP)](12_AMDP.md)|Covers ABAP Managed Database Procedures (AMDP): AMDP Procedures and AMDP Functions (including CDS Table Functions)|[zcl_demo_abap_amdp](./src/zcl_demo_abap_amdp.clas.abap)| -|[Program Flow Logic](13_Program_Flow_Logic.md)|Deals with control structures (`IF`, `CASE`), loops (`DO`, `WHILE`) and exception handling|[zcl_demo_abap_prog_flow_logic](./src/zcl_demo_abap_prog_flow_logic.clas.abap)| -|[ABAP Unit Tests](14_ABAP_Unit_Tests.md)|Contains basic information about unit testing in ABAP|[zcl_demo_abap_unit_test](./src/zcl_demo_abap_unit_test.clas.abap)| -|[CDS View Entities](15_CDS_View_Entities.md)|Note that cheat sheet content is available in [this blog](https://blogs.sap.com/2022/10/24/feature-matrix-data-modeling-with-abap-core-data-services/). The focus here is on the example CDS artifacts and the [executable example class](./src/zcl_demo_abap_cds_ve.clas.abap), which include comments.|[zcl_demo_abap_cds_ve](./src/zcl_demo_abap_cds_ve.clas.abap)| -|[SAP LUW](17_SAP_LUW.md)|Provides a high-level overview of the [SAP LUW](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abensap_luw_glosry.htm) concept that deals with data consistency with a focus on SAP LUW-related statements
💡 Several statements covered in the cheat sheet and the executable example are only relevant to [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm).|Program `ZDEMO_ABAP_SAP_LUW`| -|[Dynpro](18_Dynpro.md)|Provides a high-level overview of dynpro topics with a focus on dynpro-related statements
💡 The content of this cheat sheet and the executable example are only relevant to [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm).|Program `ZDEMO_ABAP_DYNPRO`| -|[Selection Screens and Classic Lists](20_Selection_Screens_Lists.md)|Provides a high-level overview of selection screens and classic lists with a focus on related statements. It includes an excursion into the SAP List Viewer (ALV).
💡 The content of this cheat sheet and the executable examples are only relevant to [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm).|Program `ZDEMO_ABAP_SELSCR_LISTS_INTRO` (the "intro" program, from which the other related example programs can be started)| -|[Working with XML and JSON in ABAP](21_XML_JSON.md)|Covers processing XML using class libraries, XML transformations using XSLT and Simple Transformations (ST), serializations (ABAP to XML) and deserializations (XML to ABAP), dealing with JSON data|[zcl_demo_abap_xml_json](./src/zcl_demo_abap_xml_json.clas.abap)| -|[Misc ABAP Classes](22_Misc_ABAP_Classes.md)|Contains a selection of ABAP classes, serving as a quick introduction, along with code snippets to explore the functionality in action|-| - -
- -## 🎬 Getting Started with the Examples - -The main focus of the ABAP Cheat Sheets is ABAP Cloud. The examples in the *main* branch of the repository are designed to be imported into the SAP BTP ABAP environment. -For classic ABAP, you can find examples in the other branches of the repository that you can import into your sandbox SAP system. Just select the appropriate version (*v757* stands for ABAP version 7.57). Check the information in the following collapsible sections for your system environment and perform the required steps. - -
- 1) General info -
- -- Some **DDIC artifacts**, such as database tables, are part of the repository. They are used by the examples to ensure self-contained examples. All artifacts must be imported for all examples to work. -- Most examples are designed to **display some output in the ADT console**. Once successfully imported, you can **run** the examples in ADT by choosing *F9* to display the output in the ADT console. The programs included in the branches for classic ABAP can be executed with *F8*. -- The examples **include descriptions and comments** in the code to provide explanations and set the context. -
- -
- 2a) SAP BTP ABAP environment -
- -**Prerequisites** -- [x] You have access to an SAP BTP ABAP Environment instance (see [here](https://blogs.sap.com/2018/09/04/sap-cloud-platform-abap-environment) for additional information). -- [x] You have downloaded and installed the ABAP development tools for Eclipse (ADT). Make sure that you are using the latest version, as indicated on the [installation page](https://tools.hana.ondemand.com/#abap). -- [x] Before importing the code, you have performed a system-wide search for classes named `ZCL_DEMO_ABAP*`, for example, so that you do not run into errors when you try to import the code. If someone has already imported the content into the system, you can simply check out that imported version and proceed to the step *3) Run the code*. -- [x] You have created an ABAP cloud project in ADT that allows you to access your SAP BTP ABAP Environment instance (see [here](https://help.sap.com/viewer/5371047f1273405bb46725a417f95433/Cloud/en-US/99cc54393e4c4e77a5b7f05567d4d14c.html) for more information). Your login language is English. -- [x] You have installed the [abapGit](https://github.com/abapGit/eclipse.abapgit.org) plug-in for ADT from the [update site](http://eclipse.abapgit.org/updatesite/). - - -**Import Code** - -Use the abapGit plug-in to install the ABAP Cheat Sheets by carrying out the following steps: - -1. In your ABAP cloud project, create a package, for example, *ZABAP_CHEAT_SHEETS* as the target package. It is recommended that you assign the package to a transport request that is suitable for demo content. -2. Add the package to the *Favorite Packages* in the *Project Explorer* view in ADT. -3. To add the abapGit Repositories view to the ABAP perspective, choose *Window* → *Show View* → *Other...* from the menu bar and choose *abapGit Repositories*. -4. In the abapGit Repositories view, click the `+` icon in the upper right corner of the ADT tab to link a new abapGit repository. -
![ADT](./files/abapGit_Repositories.png) - -5. The *Link abapGit Repository* popup appears. Enter the following URL: - -``` -https://github.com/SAP-samples/abap-cheat-sheets.git -``` - -6. Choose *Next*. - -7. On the *Branch and Package Selection* screen, enter the name of the created package (for example, *ZABAP_CHEAT_SHEETS*) in the *Package* field. -8. Choose *Next*. -9. On the *Select Transport Request* screen, select the created transport request that is suitable for the demo content and choose *Finish* to link the Git repository to your ABAP cloud project. If the created package is already assigned to a transport request for the demo content, and a message appears that an object is already locked in a transport request, choose *Finish*, too. -10. In the *abapGit Repositories* view, filter for your package. The repository appears in the *abapGit Repositories* view with the status Linked. -11. Right-click on the new abapGit repository and choose *Pull...* to start the cloning of the repository contents. -12. On the *Branch and Package Selection* screen, choose *Next*. -13. If the *Locally Modified Object* screen is displayed, select the objects (for example, the package to automatically select all artifacts) from the list and choose *Next*. -14. On the next screen, select a transport request and choose *Finish*. Same as above, if an *object already locked* message is displayed, choose *Finish* as well. The status in the *abapGit Repositories* view changes to Pull running.... Note that the pull run may take several minutes. -15. Once the cloning is complete, the status changes to *Pulled Successfully*. You may need to refresh the *abapGit Repositories* view to see the progress of the import. To do this, choose the *Refresh* icon in the upper right corner of the view. -16. Refresh your project tree. For example, in ADT, right-click the package and choose *Refresh*. The package should contain all the artifacts from the GitHub repository. -17. Make sure that all artifacts are active. To activate all inactive development objects, choose the *Activate all inactive ABAP development objects* button from the menu (or choose *CTRL+Shift+F3*). -
- -
- 2b) Classic ABAP (on-premise ABAP systems) -
- -**Prerequisites** -- [x] You are running an [ABAP release](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abennews-75.htm) for which examples are available. See the different branches of the repository. For example, you can find out about your ABAP release by checking the value of `sy-saprl`: - ```abap - DATA rel LIKE sy-saprl. - rel = sy-saprl. - BREAK-POINT. - ``` -- [x] Before importing the code, you have performed a system-wide search for classes named *ZCL_DEMO_ABAP**, for example, to avoid errors when you try to import the code. If someone has already imported the content into the system, you can simply check out that imported version and proceed to the step *3) Run the code*. -- [x] You have downloaded and installed the ABAP development tools for Eclipse (ADT). Make sure that you are using the latest version, as indicated on the [installation page](https://tools.hana.ondemand.com/#abap). -- [x] You have created an ABAP project in ADT that allows you to access your application server as mentioned above. Your login language is English. -- [x] You have downloaded and installed the standalone version of the abapGit report. Make sure you are using the latest version, as indicated on the [installation page](https://docs.abapgit.org/). You can create a report, for example, *zabapgit_standalone*, and copy and paste [this code](https://raw.githubusercontent.com/abapGit/build/main/zabapgit_standalone.prog.abap) into the program. - -**Import Code** - -Use the standalone version of the abapGit report to import the demo examples of the ABAP cheat sheets by performing the following steps: -1. In your ABAP project, create a package, such as *TEST_ABAP_CHEAT_SHEETS* as a target package suitable for demo content (for example, by using *LOCAL* as the software component). -2. Add the package to the *Favorite Packages* in the *Project Explorer* view in ADT. -3. Run the standalone version of the abapGit report. -4. Choose the *New Online* button. If the button is not available, for example, if another repository is already open, choose the *Repository List* button. -5. On the *New Online Repository* screen, make the following entries: - - ***Git Repository URL***: - - ``` - https://github.com/SAP-samples/abap-cheat-sheets.git - ``` - - - ***Package***: Your demo package, for example, *TEST_ABAP_CHEAT_SHEETS* - - ***Branch***: Choose the button with the 3 dots to the right of the input field. In the pop-up window, select the appropriate branch, e.g. *v757* if your ABAP release is 7.57, and choose the *Continue* (✔️) button. **Note**: The examples in the *main* branch are for ABAP Cloud only. - - ***Folder Logic***: *Full* -6. Choose *Create Online Repo*. -7. The *Repository* screen displays the available ABAP artifacts to be imported into your ABAP system. -8. Choose the *Pull* button. The import of the artifacts is triggered. This may take a while. -9. If the *Inactive Objects* popup is displayed, select all artifacts and choose *Continue* (✔️). -10. When the cloning is complete, refresh your project tree. For example, in ADT, right-click on the package and choose *Refresh*. The package should contain all artifacts from the GitHub repository. -11. Make sure that all artifacts are active. To activate all inactive development objects, choose the *Activate all inactive ABAP development objects* button from the menu (or choose *CTRL+Shift+F3*). - -
- -
- 3) Run the code -
- -- Open the package you created containing the imported ABAP artifacts in the ABAP development tools for Eclipse (ADT). -- Classes: - - Open one of the ABAP cheat sheet example classes listed in the [ABAP Cheat Sheets Overview](#-abap-cheat-sheets-overview) section, for example, *zcl_demo_abap_string_proc*. The classes are located in the *Source Code Library* → *Classes* folder. - - Choose *F9* to run the class. Alternatively, choose *Run* → *Run As* → *2 ABAP Application (Console)* from the menu. - - Check the console output. - > **💡 Note**
- >- Check the notes on the context and the ABAP syntax used that are included as comments in the class. - >- Due to the amount of output in the console, the examples include numbers (e.g. 1) ..., 2) ..., 3) ...) that represent the headers of each example code section. Also, in most cases, the variable name is displayed in the console. Therefore, to find the relevant output in the console more easily and quickly, simply search the console for the number (e.g. search for *3)* for the particular output) or variable name (*CTRL+F* in the console), or use breakpoints in the code to check variables in the debugger. - >- You may want to clear the console by right-clicking in the console and choosing *Clear* before running another demo class to avoid confusing the output of multiple classes. -- Programs: - - The programs included in the repository can be executed with *F8* (or *Run* → *Run As* → *1 ABAP Application*). - - -
- -
- -## ⚡ Known Issues -- Only one user on the system can import this repository because all object names must be globally unique. Before importing the code, you should perform a system-wide search for classes named *ZCL_DEMO_ABAP**, for example. If someone has already imported the content into the system, you can simply check out that imported code. -- Regarding possible code check warnings, e.g. for the many strings in the code, not using an `ORDER BY` clause, or messages regarding using `SELECT *`, the code deliberately avoids [pragmas](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenpragma_glosry.htm) and [pseudo comments](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenpseudo_comment_glosry.htm) in order to focus on the available ABAP syntax. See also the [Disclaimer](#%EF%B8%8F-disclaimer). -- Regarding the examples to be imported into on-premise ABAP systems, note the following: The cheat sheet documents cover ABAP syntax regardless of the ABAP release to avoid scattering information and to have the information in one place. Therefore, the lower the release, the fewer syntax options and examples are available. For example, the RAP examples in particular require at least ABAP version 7.56. The code examples in the classic ABAP branches do not necessarily reflect all (described) syntax variations and options that are available in classic ABAP and in the particular ABAP release. - -
- -## ℹ️ More Information -- For the system-internal version of the ABAP Keyword Documentation in - - ... **classic ABAP**: Access the documentation in the SAP GUI via the transactions `ABAPDOCU` (opens the documentation directly) and `ABAPHELP` (opens an input field with which you can search the documentation content, for example, you can search for a keyword such as `SELECT`). Or, of course, choose `F1` on a keyword in your code. If you are in the SAP GUI (e.g. in `SE80`), the system-internal version opens. If you are in ADT, the documentation opens in the *ABAP Language Help* view. - - ... **ABAP Cloud**: In ADT, the documentation is in the *ABAP Language Help* view, where you can also search. If you choose `F1` on a keyword in your code, the documentation opens there. -- Links to the online version of the ABAP Keyword Documentation for: - - **Standard ABAP**: Unrestricted ABAP language scope for [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm) → [Online version of the documentation (latest version)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap.htm). To access the online documentation for a specific ABAP version, e.g. 7.54, you can select the version from the drop-down list [here](https://help.sap.com/docs/ABAP?locale=en-US) (*latest* is preselected). The *ABAP* link under *Development* will take you to the documentation of choice. - - **ABAP for Cloud Development**: Restricted ABAP language scope for developments, for example, in the SAP BTP ABAP environment → [Online version of the documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm) -- For demonstration examples of the ABAP Keyword Documentation in classic ABAP, see the `SABAPDEMOS` package. This package contains all the examples used in the ABAP Keyword Documentation. For the context, class/program name, etc., see the [example page](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_examples.htm), which is also available in the system-internal SAP GUI version as a node in the topic tree and which summarizes the executable examples. Of course, you can also find the example topics in the context of the individual topic of the ABAP keyword documentation. The example topics are marked with a ⚙️ icon: - - ![](./files/example_topics.png) - -
- -## ⚠️ Disclaimer -The code examples presented in this repository are only syntax examples and are not intended for direct use in a production system environment. The code examples are primarily intended to provide a better explanation and visualization of the syntax and semantics of ABAP statements and not to solve concrete programming tasks. For production application programs, a dedicated solution should therefore always be worked out for each individual case. -There is no guarantee for either the correctness or the completeness of the code. In addition, there is no legal responsibility or liability for possible errors or their consequences, which occur through the use of the example code. - -
- -## 📟 Support -This is not intended to be a contribution repository, so please do not create pull requests. If you like to address issues or suggestions regarding additional syntax to be covered, please create an issue. However, this project is provided "as-is": there is no guarantee that raised issues will be answered or addressed in future releases. - -
- -## 📜 License -Copyright (c) 2022 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSE) file. - +
+
+ + ABAP Keyword Documentation + + +

ABAP Cheat Sheets

+ +

+ Explore ABAP syntax in a nutshell & executable examples +
+ +
+ How to Use + · + Cheat Sheets + · + Examples +

+
+
+
+
+ +[![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/abap-cheat-sheets)](https://api.reuse.software/info/github.com/SAP-samples/abap-cheat-sheets) + +ABAP cheat sheets[^1] ... +- provide a **collection of information on selected ABAP topics** in a nutshell for your reference. +- focus on **ABAP syntax**. +- include **code snippets**. +- are supported by easy-to-consume **demonstration examples** that you can import into your [SAP BTP ABAP environment](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensap_btp_abap_env_glosry.htm) (*main* branch; ABAP language version: [ABAP for Cloud Development](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_for_cloud_dev_glosry.htm)) or on-premise ABAP system ([classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm); the repository branches other than *main*) using [abapGit](https://abapgit.org/) to run and check out ABAP syntax in action in simple contexts. +- are enriched by links to glossary entries and chapters of the **ABAP Keyword Documentation** (the *F1 help*) and more for you to deep dive into the respective ABAP topics and get more comprehensive information. + +
+💡 Note +
+ +- Since the ABAP cheat sheets provide information in a nutshell, they do not claim to be fully comprehensive as far as the described syntax and concepts are concerned. If you need more details, you can always consult the ABAP Keyword Documentation, for example, by choosing *F1* on a keyword in your code, or by searching directly using the online or the system-internal version. +- Unless otherwise stated in the cheat sheets, the content of this repository is relevant for these ABAP language versions (with a focus on the first): + - [ABAP for Cloud Development](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_for_sap_cloud_glosry.htm): Restricted ABAP language scope for [ABAP Cloud](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_cloud_glosry.htm) → [Online version of the documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm) + - [Standard ABAP](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenstandard_abap_glosry.htm): Unrestricted ABAP language scope, for example, for [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm) → [Online version of the documentation (latest version)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap.htm) +- Check the [Known Issues](#-known-issues) and [Disclaimer](#%EF%B8%8F-disclaimer). +- The cheat sheets provide links to glossary entries and topics in the ABAP Keyword Documentation. Note that unlike the classic ABAP-only cheat sheets, in most cases these links refer to ABAP for Cloud Development. +- [Here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrestricted_abap_elements.htm) is an overview of the different ABAP language elements in the different ABAP versions, i.e. what is allowed in ABAP Cloud and what is not. See also the released APIs [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenreleased_apis.htm). +- In order to have all ABAP cheat sheet documents in one place, the *main* branch (for ABAP Cloud examples) also contains the ABAP cheat sheet documents that are only relevant for classic ABAP. +- The example classes contained in the branches for classic ABAP mostly use syntax that is also available in ABAP for Cloud Development. Only the `TEST_ABAP_CHEAT_SHEETS_CLASSIC` subpackage contains syntax relevant to Standard ABAP and that is not available in ABAP for Cloud Development, such as dynpro-related ABAP keywords. +
+ +
+ +## 🏗️ How to Use + +1. **ABAP syntax info**: Get info in a nutshell on ABAP syntax and concepts related to various ABAP topics in the [ABAP cheat sheets](#-abap-cheat-sheets-overview). +2. **Demo examples**: Import the ABAP development objects of this repository (Note: *main* branch for ABAP Cloud only) into your system using [abapGit](https://abapgit.org/) as described [here](#-getting-started-with-the-examples) and run the demo classes by choosing *F9* in the [ABAP development tools for Eclipse (ADT)](https://tools.eu1.hana.ondemand.com/) for checking out the ABAP syntax in action. + +
+ +## 📝 ABAP Cheat Sheets Overview + +| Cheat Sheet | Topics Covered | Demo Example | +| ------------- | ------------- | ----- | +|[ABAP for Cloud Development](19_ABAP_for_Cloud_Development.md)| Briefly outlines the terms ABAP Cloud and classic ABAP to set the context for ABAP for Cloud Development | [zcl_demo_abap_cloud_excursion](./src/zcl_demo_abap_cloud_excursion.clas.abap) (see the notes in the cheat sheet) | +|[Data Types and Data Objects](16_Data_Types_and_Objects.md)| Contains basic information about data types and data objects in ABAP | [zcl_demo_abap_dtype_dobj](./src/zcl_demo_abap_dtype_dobj.clas.abap) | +|[Internal Tables](01_Internal_Tables.md)| Creating, filling, reading from, sorting, modifying internal tables | [zcl_demo_abap_internal_tables](./src/zcl_demo_abap_internal_tables.clas.abap) | +|[Structures](02_Structures.md)| Some basics when working with structures | [zcl_demo_abap_structures](./src/zcl_demo_abap_structures.clas.abap) | +|[ABAP SQL](03_ABAP_SQL.md)| Reading from database tables using `SELECT`, changing data in database tables using `INSERT`, `UPDATE`, `MODIFY` and `DELETE` | [zcl_demo_abap_sql](./src/zcl_demo_abap_sql.clas.abap) | +|[ABAP Object Orientation](04_ABAP_Object_Orientation.md)| Working with objects and components, concepts such as inheritance, interfaces, and more | [zcl_demo_abap_objects](./src/zcl_demo_abap_objects.clas.abap) | +|[Constructor Expressions](05_Constructor_Expressions.md)| Covers constructor expressions with operators such as `VALUE`, `CORRESPONDING`, `NEW`, `CONV`, `EXACT`, `REF`, `CAST`, `COND`, `SWITCH`, `FILTER`, `REDUCE`, iteration expressions with `FOR`, `LET` expressions | [zcl_demo_abap_constructor_expr](./src/zcl_demo_abap_constructor_expr.clas.abap) | +|[Dynamic Programming](06_Dynamic_Programming.md)| Covers field symbols and data references as supporting elements for dynamic programming, dynamic ABAP syntax components, runtime type services (RTTS), i. e. runtime type identification (RTTI) and runtime type creation (RTTC) | [zcl_demo_abap_dynamic_prog](./src/zcl_demo_abap_dynamic_prog.clas.abap) | +|[String Processing](07_String_Processing.md)| Creating strings and assigning values, chaining strings, string templates, concatenating, splitting, modifying strings, searching and replacing, regular expressions | [zcl_demo_abap_string_proc](./src/zcl_demo_abap_string_proc.clas.abap) | +|[ABAP for RAP: Entity Manipulation Language (ABAP EML)](08_EML_ABAP_for_RAP.md)| Setting EML in the context of RAP, standard (create, read, update, delete) and non-standard operations (actions) |
  • [Demo RAP scenario with a managed RAP BO, external numbering (zcl_demo_abap_rap_ext_num_m)](./src/zcl_demo_abap_rap_ext_num_m.clas.abap)

  • [Demo RAP scenario with an unmanaged RAP BO, external numbering (zcl_demo_abap_rap_ext_num_u)](./src/zcl_demo_abap_rap_ext_num_u.clas.abap)

  • [Demo RAP scenario ("RAP calculator") with a managed, draft-enabled RAP BO, late numbering (zcl_demo_abap_rap_draft_ln_m)](./src/zcl_demo_abap_rap_draft_ln_m.clas.abap)
    Note that this example can also be checked out using the preview version of an SAP Fiori UI. Check the comments in the class for the steps.

  • [Demonstrating the local consumption of RAP business events in the context of a RAP demo scenario, managed RAP BO with managed internal numbering and additional save (zcl_demo_abap_rap_m_as)](./src/zcl_demo_abap_rap_m_as.clas.abap)
| +|[Excursion Down to Bits and Bytes](09_Bits_and_Bytes.md)|Covers the technical background of data types and data objects|-| +|[ABAP SQL: Working with Hierarchies](10_ABAP_SQL_Hierarchies.md)|Summarizes the functions ABAP SQL offers together with ABAP CDS for working with hierarchical data that is stored in database tables|-| +|[Internal Tables: Grouping](11_Internal_Tables_Grouping.md)|Covers the `GROUP BY` clause in statements for internal tables.|[zcl_demo_abap_sql_group_by](./src/zcl_demo_abap_sql_group_by.clas.abap)| +|[ABAP Managed Database Procedures (AMDP)](12_AMDP.md)|Covers ABAP Managed Database Procedures (AMDP): AMDP Procedures and AMDP Functions (including CDS Table Functions)|[zcl_demo_abap_amdp](./src/zcl_demo_abap_amdp.clas.abap)| +|[Program Flow Logic](13_Program_Flow_Logic.md)|Deals with control structures (`IF`, `CASE`), loops (`DO`, `WHILE`) and exception handling|[zcl_demo_abap_prog_flow_logic](./src/zcl_demo_abap_prog_flow_logic.clas.abap)| +|[ABAP Unit Tests](14_ABAP_Unit_Tests.md)|Contains basic information about unit testing in ABAP|[zcl_demo_abap_unit_test](./src/zcl_demo_abap_unit_test.clas.abap)| +|[CDS View Entities](15_CDS_View_Entities.md)|Note that cheat sheet content is available in [this blog](https://blogs.sap.com/2022/10/24/feature-matrix-data-modeling-with-abap-core-data-services/). The focus here is on the example CDS artifacts and the [executable example class](./src/zcl_demo_abap_cds_ve.clas.abap), which include comments.|[zcl_demo_abap_cds_ve](./src/zcl_demo_abap_cds_ve.clas.abap)| +|[SAP LUW](17_SAP_LUW.md)|Provides a high-level overview of the [SAP LUW](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abensap_luw_glosry.htm) concept that deals with data consistency with a focus on SAP LUW-related statements
💡 Several statements covered in the cheat sheet and the executable example are only relevant to [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm).|Program `ZDEMO_ABAP_SAP_LUW`| +|[Dynpro](18_Dynpro.md)|Provides a high-level overview of dynpro topics with a focus on dynpro-related statements
💡 The content of this cheat sheet and the executable example are only relevant to [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm).|Program `ZDEMO_ABAP_DYNPRO`| +|[Selection Screens and Classic Lists](20_Selection_Screens_Lists.md)|Provides a high-level overview of selection screens and classic lists with a focus on related statements. It includes an excursion into the SAP List Viewer (ALV).
💡 The content of this cheat sheet and the executable examples are only relevant to [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm).|Program `ZDEMO_ABAP_SELSCR_LISTS_INTRO` (the "intro" program, from which the other related example programs can be started)| +|[Working with XML and JSON in ABAP](21_XML_JSON.md)|Covers processing XML using class libraries, XML transformations using XSLT and Simple Transformations (ST), serializations (ABAP to XML) and deserializations (XML to ABAP), dealing with JSON data|[zcl_demo_abap_xml_json](./src/zcl_demo_abap_xml_json.clas.abap)| +|[Misc ABAP Classes](22_Misc_ABAP_Classes.md)|Contains a selection of ABAP classes, serving as a quick introduction, along with code snippets to explore the functionality in action|-| + +
+ +## 🎬 Getting Started with the Examples + +The main focus of the ABAP Cheat Sheets is ABAP Cloud. The examples in the *main* branch of the repository are designed to be imported into the SAP BTP ABAP environment. +For classic ABAP, you can find examples in the other branches of the repository that you can import into your sandbox SAP system. Just select the appropriate version (*v757* stands for ABAP version 7.57). Check the information in the following collapsible sections for your system environment and perform the required steps. + +
+ 1) General info +
+ +- Some **DDIC artifacts**, such as database tables, are part of the repository. They are used by the examples to ensure self-contained examples. All artifacts must be imported for all examples to work. +- Most examples are designed to **display some output in the ADT console**. Once successfully imported, you can **run** the examples in ADT by choosing *F9* to display the output in the ADT console. The programs included in the branches for classic ABAP can be executed with *F8*. +- The examples **include descriptions and comments** in the code to provide explanations and set the context. +
+ +
+ 2a) SAP BTP ABAP environment +
+ +**Prerequisites** +- [x] You have access to an SAP BTP ABAP Environment instance (see [here](https://blogs.sap.com/2018/09/04/sap-cloud-platform-abap-environment) for additional information). +- [x] You have downloaded and installed the ABAP development tools for Eclipse (ADT). Make sure that you are using the latest version, as indicated on the [installation page](https://tools.hana.ondemand.com/#abap). +- [x] Before importing the code, you have performed a system-wide search for classes named `ZCL_DEMO_ABAP*`, for example, so that you do not run into errors when you try to import the code. If someone has already imported the content into the system, you can simply check out that imported version and proceed to the step *3) Run the code*. +- [x] You have created an ABAP cloud project in ADT that allows you to access your SAP BTP ABAP Environment instance (see [here](https://help.sap.com/viewer/5371047f1273405bb46725a417f95433/Cloud/en-US/99cc54393e4c4e77a5b7f05567d4d14c.html) for more information). Your login language is English. +- [x] You have installed the [abapGit](https://github.com/abapGit/eclipse.abapgit.org) plug-in for ADT from the [update site](http://eclipse.abapgit.org/updatesite/). + + +**Import Code** + +Use the abapGit plug-in to install the ABAP Cheat Sheets by carrying out the following steps: + +1. In your ABAP cloud project, create a package, for example, *ZABAP_CHEAT_SHEETS* as the target package. It is recommended that you assign the package to a transport request that is suitable for demo content. +2. Add the package to the *Favorite Packages* in the *Project Explorer* view in ADT. +3. To add the abapGit Repositories view to the ABAP perspective, choose *Window* → *Show View* → *Other...* from the menu bar and choose *abapGit Repositories*. +4. In the abapGit Repositories view, click the `+` icon in the upper right corner of the ADT tab to link a new abapGit repository. +
![ADT](./files/abapGit_Repositories.png) + +5. The *Link abapGit Repository* popup appears. Enter the following URL: + +``` +https://github.com/SAP-samples/abap-cheat-sheets.git +``` + +6. Choose *Next*. + +7. On the *Branch and Package Selection* screen, enter the name of the created package (for example, *ZABAP_CHEAT_SHEETS*) in the *Package* field. +8. Choose *Next*. +9. On the *Select Transport Request* screen, select the created transport request that is suitable for the demo content and choose *Finish* to link the Git repository to your ABAP cloud project. If the created package is already assigned to a transport request for the demo content, and a message appears that an object is already locked in a transport request, choose *Finish*, too. +10. In the *abapGit Repositories* view, filter for your package. The repository appears in the *abapGit Repositories* view with the status Linked. +11. Right-click on the new abapGit repository and choose *Pull...* to start the cloning of the repository contents. +12. On the *Branch and Package Selection* screen, choose *Next*. +13. If the *Locally Modified Object* screen is displayed, select the objects (for example, the package to automatically select all artifacts) from the list and choose *Next*. +14. On the next screen, select a transport request and choose *Finish*. Same as above, if an *object already locked* message is displayed, choose *Finish* as well. The status in the *abapGit Repositories* view changes to Pull running.... Note that the pull run may take several minutes. +15. Once the cloning is complete, the status changes to *Pulled Successfully*. You may need to refresh the *abapGit Repositories* view to see the progress of the import. To do this, choose the *Refresh* icon in the upper right corner of the view. +16. Refresh your project tree. For example, in ADT, right-click the package and choose *Refresh*. The package should contain all the artifacts from the GitHub repository. +17. Make sure that all artifacts are active. To activate all inactive development objects, choose the *Activate all inactive ABAP development objects* button from the menu (or choose *CTRL+Shift+F3*). +
+ +
+ 2b) Classic ABAP (on-premise ABAP systems) +
+ +**Prerequisites** +- [x] You are running an [ABAP release](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abennews-75.htm) for which examples are available. See the different branches of the repository. For example, you can find out about your ABAP release by checking the value of `sy-saprl`: + ```abap + DATA rel LIKE sy-saprl. + rel = sy-saprl. + BREAK-POINT. + ``` +- [x] Before importing the code, you have performed a system-wide search for classes named *ZCL_DEMO_ABAP**, for example, to avoid errors when you try to import the code. If someone has already imported the content into the system, you can simply check out that imported version and proceed to the step *3) Run the code*. +- [x] You have downloaded and installed the ABAP development tools for Eclipse (ADT). Make sure that you are using the latest version, as indicated on the [installation page](https://tools.hana.ondemand.com/#abap). +- [x] You have created an ABAP project in ADT that allows you to access your application server as mentioned above. Your login language is English. +- [x] You have downloaded and installed the standalone version of the abapGit report. Make sure you are using the latest version, as indicated on the [installation page](https://docs.abapgit.org/). You can create a report, for example, *zabapgit_standalone*, and copy and paste [this code](https://raw.githubusercontent.com/abapGit/build/main/zabapgit_standalone.prog.abap) into the program. + +**Import Code** + +Use the standalone version of the abapGit report to import the demo examples of the ABAP cheat sheets by performing the following steps: +1. In your ABAP project, create a package, such as *TEST_ABAP_CHEAT_SHEETS* as a target package suitable for demo content (for example, by using *LOCAL* as the software component). +2. Add the package to the *Favorite Packages* in the *Project Explorer* view in ADT. +3. Run the standalone version of the abapGit report. +4. Choose the *New Online* button. If the button is not available, for example, if another repository is already open, choose the *Repository List* button. +5. On the *New Online Repository* screen, make the following entries: + - ***Git Repository URL***: + + ``` + https://github.com/SAP-samples/abap-cheat-sheets.git + ``` + + - ***Package***: Your demo package, for example, *TEST_ABAP_CHEAT_SHEETS* + - ***Branch***: Choose the button with the 3 dots to the right of the input field. In the pop-up window, select the appropriate branch, e.g. *v757* if your ABAP release is 7.57, and choose the *Continue* (✔️) button. **Note**: The examples in the *main* branch are for ABAP Cloud only. + - ***Folder Logic***: *Full* +6. Choose *Create Online Repo*. +7. The *Repository* screen displays the available ABAP artifacts to be imported into your ABAP system. +8. Choose the *Pull* button. The import of the artifacts is triggered. This may take a while. +9. If the *Inactive Objects* popup is displayed, select all artifacts and choose *Continue* (✔️). +10. When the cloning is complete, refresh your project tree. For example, in ADT, right-click on the package and choose *Refresh*. The package should contain all artifacts from the GitHub repository. +11. Make sure that all artifacts are active. To activate all inactive development objects, choose the *Activate all inactive ABAP development objects* button from the menu (or choose *CTRL+Shift+F3*). + +
+ +
+ 3) Run the code +
+ +- Open the package you created containing the imported ABAP artifacts in the ABAP development tools for Eclipse (ADT). +- Classes: + - Open one of the ABAP cheat sheet example classes listed in the [ABAP Cheat Sheets Overview](#-abap-cheat-sheets-overview) section, for example, *zcl_demo_abap_string_proc*. The classes are located in the *Source Code Library* → *Classes* folder. + - Choose *F9* to run the class. Alternatively, choose *Run* → *Run As* → *2 ABAP Application (Console)* from the menu. + - Check the console output. + > **💡 Note**
+ >- Check the notes on the context and the ABAP syntax used that are included as comments in the class. + >- Due to the amount of output in the console, the examples include numbers (e.g. 1) ..., 2) ..., 3) ...) that represent the headers of each example code section. Also, in most cases, the variable name is displayed in the console. Therefore, to find the relevant output in the console more easily and quickly, simply search the console for the number (e.g. search for *3)* for the particular output) or variable name (*CTRL+F* in the console), or use breakpoints in the code to check variables in the debugger. + >- You may want to clear the console by right-clicking in the console and choosing *Clear* before running another demo class to avoid confusing the output of multiple classes. +- Programs: + - The programs included in the repository can be executed with *F8* (or *Run* → *Run As* → *1 ABAP Application*). + + +
+ +
+ +## ⚡ Known Issues +- Only one user on the system can import this repository because all object names must be globally unique. Before importing the code, you should perform a system-wide search for classes named *ZCL_DEMO_ABAP**, for example. If someone has already imported the content into the system, you can simply check out that imported code. +- Regarding possible code check warnings, e.g. for the many strings in the code, not using an `ORDER BY` clause, or messages regarding using `SELECT *`, the code deliberately avoids [pragmas](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenpragma_glosry.htm) and [pseudo comments](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenpseudo_comment_glosry.htm) in order to focus on the available ABAP syntax. See also the [Disclaimer](#%EF%B8%8F-disclaimer). +- Regarding the examples to be imported into on-premise ABAP systems, note the following: The cheat sheet documents cover ABAP syntax regardless of the ABAP release to avoid scattering information and to have the information in one place. Therefore, the lower the release, the fewer syntax options and examples are available. For example, the RAP examples in particular require at least ABAP version 7.56. The code examples in the classic ABAP branches do not necessarily reflect all (described) syntax variations and options that are available in classic ABAP and in the particular ABAP release. +- If you encounter import problems with the XSLT/ST objects, try to manually paste the code from the `...source.xml` files [here](https://github.com/SAP-samples/abap-cheat-sheets/tree/main/src) into the improperly imported objects and activate all non-active objects. + +
+ +## ℹ️ More Information +- For the system-internal version of the ABAP Keyword Documentation in + - ... **classic ABAP**: Access the documentation in the SAP GUI via the transactions `ABAPDOCU` (opens the documentation directly) and `ABAPHELP` (opens an input field with which you can search the documentation content, for example, you can search for a keyword such as `SELECT`). Or, of course, choose `F1` on a keyword in your code. If you are in the SAP GUI (e.g. in `SE80`), the system-internal version opens. If you are in ADT, the documentation opens in the *ABAP Language Help* view. + - ... **ABAP Cloud**: In ADT, the documentation is in the *ABAP Language Help* view, where you can also search. If you choose `F1` on a keyword in your code, the documentation opens there. +- Links to the online version of the ABAP Keyword Documentation for: + - **Standard ABAP**: Unrestricted ABAP language scope for [classic ABAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclassic_abap_glosry.htm) → [Online version of the documentation (latest version)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap.htm). To access the online documentation for a specific ABAP version, e.g. 7.54, you can select the version from the drop-down list [here](https://help.sap.com/docs/ABAP?locale=en-US) (*latest* is preselected). The *ABAP* link under *Development* will take you to the documentation of choice. + - **ABAP for Cloud Development**: Restricted ABAP language scope for developments, for example, in the SAP BTP ABAP environment → [Online version of the documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm) +- For demonstration examples of the ABAP Keyword Documentation in classic ABAP, see the `SABAPDEMOS` package. This package contains all the examples used in the ABAP Keyword Documentation. For the context, class/program name, etc., see the [example page](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenabap_examples.htm), which is also available in the system-internal SAP GUI version as a node in the topic tree and which summarizes the executable examples. Of course, you can also find the example topics in the context of the individual topic of the ABAP keyword documentation. The example topics are marked with a ⚙️ icon: + + ![](./files/example_topics.png) + +
+ +## ⚠️ Disclaimer +The code examples presented in this repository are only syntax examples and are not intended for direct use in a production system environment. The code examples are primarily intended to provide a better explanation and visualization of the syntax and semantics of ABAP statements and not to solve concrete programming tasks. For production application programs, a dedicated solution should therefore always be worked out for each individual case. +There is no guarantee for either the correctness or the completeness of the code. In addition, there is no legal responsibility or liability for possible errors or their consequences, which occur through the use of the example code. + +
+ +## 📟 Support +This is not intended to be a contribution repository, so please do not create pull requests. If you like to address issues or suggestions regarding additional syntax to be covered, please create an issue. However, this project is provided "as-is": there is no guarantee that raised issues will be answered or addressed in future releases. + +
+ +## 📜 License +Copyright (c) 2022 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSE) file. + [^1]: "A written [...] aid (such as a sheet of notes) that can be referred to for help in understanding or remembering something complex" (Definition for "cheat sheet" in Merriam-Webster Dictionary). \ No newline at end of file diff --git a/src/zcl_demo_abap_xml_json.clas.abap b/src/zcl_demo_abap_xml_json.clas.abap index d9c038a..6ecd7c3 100644 --- a/src/zcl_demo_abap_xml_json.clas.abap +++ b/src/zcl_demo_abap_xml_json.clas.abap @@ -1,1585 +1,1585 @@ -*********************************************************************** -* -* ABAP cheat sheet: Working with XML and JSON in ABAP -* -* -------------------------- PURPOSE ---------------------------------- -* - Example that demonstrates working with XML and JSON in ABAP. -* - The following topics are covered:* -* - Processing XML using class libraries (iXML, sXML) -* - XML Transformations using XSLT and Simple Transformations -* - CALL TRANSFORMATION syntax -* - Dealing with JSON data, XCO classes for JSON -* - Excursions: Converting string <-> xstring, compressing and -* decompressing binary data -* -* ----------------------- GETTING STARTED ----------------------------- -* - Open the class with the ABAP development tools for Eclipse (ADT). -* - Choose F9 to run the class. -* - Check the console output. -* - To understand the context and the ABAP syntax used, refer to the -* notes included in the class as comments or refer to the respective -* topic in the ABAP Keyword Documentation. -* - Due to the amount of console output, the examples contain numbers -* (e.g. 1) ..., 2) ..., 3) ...) for the individual example sections. -* Also, the variable name is displayed in most cases. So to find -* the relevant output in the console easier and faster, just search -* for the number/variable name in the console (CTRL+F in the console) -* or use the debugger. -* -* ----------------------------- NOTE ----------------------------------- -* The code presented in this class is intended only to support the ABAP -* cheat sheets. It is not intended for direct use in a production system -* environment. The code examples in the ABAP cheat sheets are primarily -* intended to provide a better explanation and visualization of the -* syntax and semantics of ABAP statements, not to solve concrete -* programming tasks. For production application programs, you should -* always work out your own solution for each individual case. There is -* no guarantee for the correctness or completeness of the code. -* Furthermore, there is no legal responsibility or liability for any -* errors or their consequences that may occur when using the the example -* code. -* -*********************************************************************** -"!

ABAP cheat sheet: Working with XML and JSON in ABAP

-"! Example that demonstrates working with XML and JSON in ABAP..
Choose F9 in ADT to run the class. -CLASS zcl_demo_abap_xml_json DEFINITION - PUBLIC - FINAL - CREATE PUBLIC . - - PUBLIC SECTION. - INTERFACES: if_oo_adt_classrun, - "This interface is implemented for serializing and - "deserialzing instances of classes (objects). - if_serializable_object. - CLASS-METHODS class_constructor. - - PROTECTED SECTION. - PRIVATE SECTION. - CLASS-METHODS format IMPORTING input TYPE data - xml TYPE abap_bool DEFAULT abap_true - RETURNING VALUE(string) TYPE string. - TYPES c50 TYPE c LENGTH 50. - TYPES c50_tab_type TYPE TABLE OF c50 WITH EMPTY KEY. - TYPES x30 TYPE x LENGTH 30. - TYPES x30_tab_type TYPE TABLE OF x30 WITH EMPTY KEY. - - "The following instance attribues and methods are used for serializing and - "deserialzing instances of classes (objects) - DATA: attr_string_a TYPE string, - attr_string_b TYPE string, - attr_concat_string TYPE string, - attr_lowercase_str TYPE string. - METHODS: concatenate_string, - lowercase_string, - "The following method can only have output parameters. - "For each output parameter of the serialize_helper method, you must specify - "an identically named input parameter of the deserialize_helper method - "with the same type. - serialize_helper EXPORTING attr_string_a TYPE string - attr_string_b TYPE string - attr_concat_string TYPE string, - "This method can only have input parameters. - deserialize_helper IMPORTING attr_string_a TYPE string - attr_string_b TYPE string - attr_concat_string TYPE string. -ENDCLASS. - - - -CLASS zcl_demo_abap_xml_json IMPLEMENTATION. - - METHOD if_oo_adt_classrun~main. - - out->write( |ABAP Cheat Sheet Example: Working with XML and JSON in ABAP\n\n| ). - out->write( |1) Excursion: Converting string <-> xstring| ). - "In the following examples, many operations are performed using binary data. - "This excursion shows the conversion of string to xstring and the other way round - "using a codepage. The examples use UTF-8. - "For this purpose, you can, for example, use the cl_abap_conv_codepage class - "and the XCO library. - - "Storing XML data in a data object of type string - DATA(xml_string) = - `` && - ` ` && - ` LH` && - ` 400` && - ` ` && - ` Frankfurt` && - ` FRA` && - ` ` && - ` ` && - ` ` && - ` Berlin` && - ` SXF` && - ` ` && - ` ` && - ` ` && - ` ` && - ` DL` && - ` 1984` && - ` ` && - ` San Francisco` && - ` SFO` && - ` ` && - ` ` && - ` ` && - ` New York` && - ` JFK` && - ` ` && - ` ` && - ` ` && - ``. - - "string -> xstring - "Note: UTF-8 is used by default. Here, it is specified explicitly. - "Conversion errors are caught using the cx_sy_conversion_codepage class. - TRY. - DATA(conv_xstring) = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( xml_string ). - CATCH cx_sy_conversion_codepage. - ENDTRY. - - "xstring -> string - DATA(conv_string) = cl_abap_conv_codepage=>create_in( )->convert( conv_xstring ). - - "As an alternative, you can use methods of the XCO library. - "string -> xstring - DATA(conv_xstring_xco) = xco_cp=>string( xml_string - )->as_xstring( xco_cp_character=>code_page->utf_8 - )->value. - - "xstring -> string - DATA(conv_string_xco) = xco_cp=>xstring( conv_xstring_xco - )->as_string( xco_cp_character=>code_page->utf_8 - )->value. - - conv_string = format( conv_string ). - conv_string_xco = format( conv_string_xco ). - out->write( |\n| ). - out->write( `Results of the xstring to string conversions:` ). - out->write( |\n| ). - out->write( conv_string ). - out->write( |\n| ). - out->write( conv_string_xco ). - -********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `2) Processing XML Using Class Libraries` ) ). - out->write( |Excursion: Usable iXML/sXML Classes and Interfaces\n\n| ). - "Using a released CDS view, classes and interfaces are retrieved that - "have 'ixml' and 'sxml' in the name for you to explore the released classes - "and interfaces in this context. - - SELECT ReleasedObjectType, ReleasedObjectName, ReleaseState - FROM i_apisforclouddevelopment - WHERE releasestate = 'RELEASED' - AND - ( ReleasedObjectType = 'CLAS' OR ReleasedObjectType = 'INTF' ) - AND - ( ReleasedObjectName LIKE '%IXML%' OR ReleasedObjectName LIKE '%SXML%' ) - INTO TABLE @DATA(released_xml_libs). - - out->write( `No output. You can check the internal table content in the debugger to view the usable artifacts.` ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `3) Creating XML Data Using iXML` ) ). - "In the following example, XML data is created using the iXML library. - "This is done by creating DOM nodes step by step. The nodes are created as - "elements and attributes. Content is inserted into the XML data. - "The example uses an appropriate attribute setting so that the result - "represents XML data in asXML format. - "Note: You can check out more examples in the system by choosing CTRL + - "SHIFT + A in ADT and search for *demo_ixml*. - "For more information on the classes/methods used, check the documentation - "by choosing F2 in ADT when placing the cursor on a class/methods. - - "Creating one factory object of the access class cl_ixml_core using the - "create method. The object is used to access the iXML library. - DATA(ixml_cr) = cl_ixml_core=>create( ). - - "Creating a document - DATA(document_cr) = ixml_cr->create_document( ). - - "Step-by-step creation of DOM nodes - "Creating a root node - DATA(root) = document_cr->create_element_ns( name = 'abap' - prefix = 'asx' ). - root->set_attribute_ns( name = 'asx' - prefix = 'xmlns' - value = 'http://www.sap.com/abapxml' ). - root->set_attribute_ns( name = 'version' - value = '1.0' ). - document_cr->append_child( root ). - DATA(xml_node1) = document_cr->create_element_ns( prefix = 'asx' - name = 'values' ). - root->append_child( xml_node1 ). - DATA(xml_node2) = document_cr->create_element_ns( name = 'STRING' ). - xml_node1->append_child( xml_node2 ). - xml_node2->append_child( document_cr->create_text( 'Hello ABAP' ) ). - - "Creating a renderer (for rendering the XML document into the output stream) - DATA xml_doc TYPE xstring. - ixml_cr->create_renderer( document = document_cr - ostream = ixml_cr->create_stream_factory( )->create_ostream_xstring( string = xml_doc ) - )->render( ). - - "Getting XML data - DATA(xml_output) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_doc ) ). - out->write( xml_output ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `4) Parsing XML Data Using iXML` ) ). - "The example covers the following aspects: - "- Parsing XML data to a DOM object in one go - "- Directly reading nodes using various iXML methods - "- Directly reading nodes using element names - "- Reading using iterators, i.e. going over the XML nodes one after another - "- During the iteration, ... - " ... node properties are extracted using various iXML methods - " (and stored in an internal table for display purposes). - " ... the XML data is modified. - " ... a new element is created. - "- Rendering XML data - - "Internal table to store node properties for display purposes - DATA properties TYPE string_table. - - "Creating simple demo XML data to be used in the example - TRY. - DATA(some_xml) = cl_abap_conv_codepage=>create_out( )->convert( - `` && - ` hallo` && - ` how` && - ` are` && - `` ). - CATCH cx_sy_conversion_codepage. - ENDTRY. - - "Creating one factory object of the access class cl_ixml_core using the - "create method. It is used to access the iXML library. - DATA(ixml_pa) = cl_ixml_core=>create( ). - "Creaing an input stream that is used for the input of XML data - DATA(stream_factory_pa) = ixml_pa->create_stream_factory( ). - "Creating an XML document stored in DOM format in the memory - DATA(document_pa) = ixml_pa->create_document( ). - "Creating a parser - "It requires the following input parameters: input stream to be parsed, - "the XML document to which the stream is parsed, a factory required to create a stream - DATA(parser_pa) = ixml_pa->create_parser( - istream = stream_factory_pa->create_istream_xstring( string = some_xml ) - document = document_pa - stream_factory = stream_factory_pa ). - - "Parsing XML data to a DOM representation in one go. It is put in the memory. - "Note: You can also parse sequentially, and not in one go. - DATA(parsing_check) = parser_pa->parse( ). - IF parsing_check = 0. "Parsing was successful - - "Directly reading nodes using various iXML methods - - "Accessing the root element of the DOM. It can be used as the initial node - "for accessing subnodes. - "You can check the content of the variables in the debugger. - "Note: Multiple methods are available to further process the nodes. - DATA(root_element) = document_pa->get_root_element( ). - "First subnode - DATA(child_element) = root_element->get_first_child( ). - "Getting the value of that node - DATA(child_element_value) = child_element->get_value( ). - "Next adjacent node/getting the value - DATA(next_element_value) = child_element->get_next( )->get_value( ). - - "Directly reading nodes using element names - "The result is the first element searched for. - DATA(element_by_name) = document_pa->find_from_name( name = `word3` )->get_value( ). - "A lot more options are available such as access by attributes. - - "Reading using iterators, i.e. going over the XML nodes sequentially - - "Creating an iterator - DATA(iterator_pa) = document_pa->create_iterator( ). - DO. - "For the iteration, you can use the get_next method to process the nodes one after another. - "Note: Here, all nodes are respected. You can also create filters to go over specific nodes. - DATA(node_i) = iterator_pa->get_next( ). - IF node_i IS INITIAL. - EXIT. - ELSE. - "Extracting properties - "For display purposes, the properties are stored in an internal table. - APPEND |gid: { node_i->get_gid( ) } / type: { node_i->get_type( ) } / name: { node_i->get_name( ) } / value: { node_i->get_value( ) }| TO properties. - ENDIF. - - IF node_i->get_type( ) = if_ixml_node=>co_node_text. - "Modifying values - "Here, the values are capitalized. - node_i->set_value( to_upper( node_i->get_value( ) ) ). - ENDIF. - - "Creating a new element - IF node_i->get_value( ) = 'are'. - document_pa->create_simple_element_ns( name = 'word4' - value = 'you' - parent = node_i->get_parent( ) ). - ENDIF. - ENDDO. - - "Creating a renderer - DATA xml_pa TYPE xstring. - ixml_pa->create_renderer( document = document_pa - ostream = ixml_pa->create_stream_factory( )->create_ostream_xstring( string = xml_pa ) - )->render( ). - - "Getting XML - DATA(output_ixml_parsing) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_pa ) ). - - out->write( output_ixml_parsing ). - out->write( |\n| ). - out->write( `Node properties:` ). - out->write( properties ). - ELSE. - out->write( `Parsing was not successful.` ). - ENDIF. - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `5) Creating XML Data Using sXML (Token-Based Rendering)` ) ). - "For sXML, there are specialized writer classes, such as CL_SXML_STRING_WRITE. - "Writers created with this class render XML data to a byte string. - "The XML 1.0 format and UTF-8 are used by default in the create method. - "Here, the parameters are specified explicitly. - "Note: The interface IF_SXML_WRITER contains the components that are valid - "for all readers (the abstract superclass CL_SXML_WRITER includes this - "interface as well as implementations for all readers). In the example below, - "a cast is required so as to access special methods (such as open_element). - - DATA(writer) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 - encoding = 'UTF-8' ) ). - - TRY. - "Creating nodes (the order of the nodes is important) - writer->open_element( name = 'flights' ). - writer->open_element( name = 'flight' ). - writer->open_element( name = 'carrier' ). - writer->write_value( 'LH' ). - writer->close_element( ). - writer->open_element( name = 'flightnumber' ). - writer->write_value( '400' ). - writer->close_element( ). - writer->close_element( ). - writer->open_element( name = 'flight' ). - writer->open_element( name = 'carrier' ). - writer->write_value( 'DL' ). - writer->close_element( ). - writer->open_element( name = 'flightnumber' ). - writer->write_value( '1984' ). - writer->close_element( ). - writer->close_element( ). - writer->close_element( ). - CATCH cx_sxml_state_error INTO DATA(error_token). - out->write( error_token->get_text( ) ). - ENDTRY. - - "Getting XML data - "The XML data can be retrieved with the GET_OUTPUT method. - "Also here, a cast is required. The result is of type xstring. - DATA(xml_sxml) = CAST cl_sxml_string_writer( writer )->get_output( ). - - DATA(output_sxml_token_rendering) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_sxml ) ). - out->write( output_sxml_token_rendering ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `6) Creating XML Data using sXML (Object-Oriented Rendering)` ) ). - - DATA(writer_oo) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 - encoding = 'UTF-8' ) ). - - TRY. - writer_oo->write_node( writer_oo->new_open_element( name = 'flights' ) ). - - writer_oo->write_node( writer_oo->new_open_element( name = 'flight' ) ). - writer_oo->write_node( writer_oo->new_open_element( name = 'carrier' ) ). - DATA(val) = writer_oo->new_value( ). - val->set_value( 'AZ' ). - writer_oo->write_node( val ). - writer_oo->write_node( writer_oo->new_close_element( ) ). - writer_oo->write_node( writer_oo->new_open_element( name = 'flightnumber' ) ). - val = writer_oo->new_value( ). - val->set_value( '788' ). - writer_oo->write_node( val ). - writer_oo->write_node( writer_oo->new_close_element( ) ). - writer_oo->write_node( writer_oo->new_close_element( ) ). - - writer_oo->write_node( writer_oo->new_open_element( name = 'flight' ) ). - writer_oo->write_node( writer_oo->new_open_element( name = 'carrier' ) ). - val = writer_oo->new_value( ). - val->set_value( 'JL' ). - writer_oo->write_node( val ). - writer_oo->write_node( writer_oo->new_close_element( ) ). - writer_oo->write_node( writer_oo->new_open_element( name = 'flightnumber' ) ). - val = writer_oo->new_value( ). - val->set_value( '407' ). - writer_oo->write_node( val ). - writer_oo->write_node( writer_oo->new_close_element( ) ). - writer_oo->write_node( writer_oo->new_close_element( ) ). - - writer_oo->write_node( writer_oo->new_close_element( ) ). - CATCH cx_sxml_state_error INTO DATA(error_oo). - out->write( error_oo->get_text( ) ). - ENDTRY. - - DATA(xml_sxml_oo_rendering) = CAST cl_sxml_string_writer( writer_oo )->get_output( ). - - DATA(output_sxml_oo_rendering) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_sxml_oo_rendering ) ). - out->write( output_sxml_oo_rendering ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `7) Parsing XML Data using sXML (Token-Based Parsing)` ) ). - - "Creating demo XML data to be used in the example - TRY. - DATA(xml_to_parse) = cl_abap_conv_codepage=>create_out( )->convert( - `` && - `` && - ` ` && - ` A` && - ` 01-01-2024` && - ` ` && - ` ` && - ` abc` && - ` def` && - ` ghi` && - ` jkl` && - ` ` && - `` ). - CATCH cx_sy_conversion_codepage. - ENDTRY. - - "Creating an internal table for display purposes - DATA: BEGIN OF node_info, - node_type TYPE string, - prefix TYPE string, - name TYPE string, - nsuri TYPE string, - value_type TYPE string, - value TYPE string, - value_raw TYPE xstring, - END OF node_info, - nodes_tab LIKE TABLE OF node_info. - - "Creating reader - "Note: See the comments for the writer above which is similar. For readers, - "the interface IF_SXML_READER exists. In this example, no special methods - "are used. Therefore, a cast is not carried out. - DATA(reader) = cl_sxml_string_reader=>create( xml_to_parse ). - "DATA(reader_cast) = CAST if_sxml_reader( cl_sxml_string_reader=>create( xml_oo ) ). - - "To iterate accros all nodes, you can call the NEXT_NODE method. - TRY. - DO. - "Check out other available methods in ADT by placing the cursor behind -> - "and choosing CTRL + Space. - reader->next_node( ). - - "When reaching the end of the XML data, the loop is exited. - IF reader->node_type = if_sxml_node=>co_nt_final. - EXIT. - ENDIF. - - "You can access the properties of the node directly. - "For display purposes, the property information is stored in an internal table. - "The demo XML data that is used here does not include all properties. Therefore, - "the values for these are initial. - - "Node type, see the interface if_sxml_node - DATA(node_type) = SWITCH #( reader->node_type WHEN if_sxml_node=>co_nt_initial THEN `CO_NT_INITIAL` - WHEN if_sxml_node=>co_nt_element_open THEN `CO_NT_ELEMENT_OPEN` - WHEN if_sxml_node=>co_nt_element_close THEN `CO_NT_ELEMENT_CLOSE` - WHEN if_sxml_node=>co_nt_value THEN `CO_NT_VALUE` - WHEN if_sxml_node=>co_nt_attribute THEN `CO_NT_ATTRIBUTE` - ELSE `Error` ). - - DATA(prefix) = reader->prefix. "Namespace prefix - DATA(name) = reader->name. "Name of the element - DATA(nsuri) = reader->nsuri. "Namespace URI - - "Value type, see the interface if_sxml_value - DATA(value_type) = SWITCH #( reader->value_type WHEN 0 THEN `Initial` - WHEN if_sxml_value=>co_vt_none THEN `CO_VT_NONE` - WHEN if_sxml_value=>co_vt_text THEN `CO_VT_TEXT` - WHEN if_sxml_value=>co_vt_raw THEN `CO_VT_RAW` - WHEN if_sxml_value=>co_vt_any THEN `CO_VT_ANY` - ELSE `Error` ). - - DATA(value) = reader->value. "Character-like value (if it is textual data) - DATA(value_raw) = reader->value_raw. "Byte-like value (if it is raw data) - - APPEND VALUE #( node_type = node_type - prefix = prefix - name = name - nsuri = nsuri - value_type = value_type - value = value - value_raw = value_raw ) TO nodes_tab. - - "Once the method is called, you can directly access the attributes of the reader with the required - "properties of the node. When the parser is on the node of an element opening, you can use the method - "NEXT_ATTRIBUTE to iterate across the XML element attributes. - IF reader->node_type = if_sxml_node=>co_nt_element_open. - DO. - reader->next_attribute( ). - IF reader->node_type <> if_sxml_node=>co_nt_attribute. - EXIT. - ENDIF. - APPEND VALUE #( node_type = `attribute` - prefix = reader->prefix - name = reader->name - nsuri = reader->nsuri - value = reader->value - value_raw = reader->value_raw ) TO nodes_tab. - ENDDO. - ENDIF. - ENDDO. - CATCH cx_sxml_state_error INTO DATA(error_parse_token). - out->write( error_parse_token->get_text( ) ). - ENDTRY. - - out->write( `Node properties:` ). - out->write( nodes_tab ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `8) Parsing XML Data using sXML (Object-Oriented Parsing)` ) ). - - CLEAR nodes_tab. - DATA(reader_oo) = cl_sxml_string_reader=>create( xml_to_parse ). - - TRY. - DO. - "To iterate accros all nodes, you can call the READ_NEXT_NODE method. - "When the end of the XML data is reached, the returned value is initial. - DATA(node_oo) = reader_oo->read_next_node( ). - IF node_oo IS INITIAL. - EXIT. - ENDIF. - - "In object-oriented parsing, methods for token-based parsing are wrapped. - "An object-oriented access to the node is provided. - "References to objects that represent the current node are returned. - - "Getting the node type - DATA(n_type) = node_oo->type. - - "If the parser is currently on the node of an element opening, - "the node object has the class CL_SXML_OPEN_ELEMENT that implements the - "interface IF_SXML_OPEN_ELEMENT. With the methods included, you can - "access the XML attributes of the element, e.g. using the GET_ATTRIBUTES - "method to put the references for all attributes into an internal table. - "To access the attributes, a downcast is required. - - CASE n_type. - WHEN if_sxml_node=>co_nt_element_open. - DATA(open_element) = CAST if_sxml_open_element( node_oo ). - - APPEND VALUE #( node_type = `open element` - prefix = open_element->prefix - name = open_element->qname-name - nsuri = open_element->qname-namespace - ) TO nodes_tab. - - DATA(attributes) = open_element->get_attributes( ). - - LOOP AT attributes INTO DATA(attribute). - APPEND VALUE #( node_type = `attribute` - prefix = open_element->prefix - name = open_element->qname-name - nsuri = open_element->qname-namespace - value = SWITCH #( attribute->value_type WHEN if_sxml_value=>co_vt_text THEN attribute->get_value( ) ) - value_raw = SWITCH #( attribute->value_type WHEN if_sxml_value=>co_vt_raw THEN attribute->get_value_raw( ) ) - ) TO nodes_tab. - ENDLOOP. - - WHEN if_sxml_node=>co_nt_element_close. - DATA(close_element) = CAST if_sxml_close_element( node_oo ). - - APPEND VALUE #( node_type = `close element` - prefix = open_element->prefix - name = open_element->qname-name - nsuri = open_element->qname-namespace - ) TO nodes_tab. - - WHEN if_sxml_node=>co_nt_value. - DATA(value_node_oo) = CAST if_sxml_value_node( node_oo ). - - APPEND VALUE #( node_type = `value` - value = SWITCH #( value_node_oo->value_type WHEN if_sxml_value=>co_vt_text THEN value_node_oo->get_value( ) ) - value_raw = SWITCH #( value_node_oo->value_type WHEN if_sxml_value=>co_vt_raw THEN value_node_oo->get_value_raw( ) ) - ) TO nodes_tab. - - WHEN OTHERS. - APPEND VALUE #( node_type = `Error` ) TO nodes_tab. - ENDCASE. - ENDDO. - CATCH cx_sxml_state_error INTO DATA(error_parse_oo). - out->write( error_parse_oo->get_text( ) ). - ENDTRY. - - out->write( `Node properties:` ). - out->write( nodes_tab ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `XML Transformations` ) ). - - out->write( |9) Excursion: Available ABAP Cheat Sheet Transformations in the System\n\n| ). - "Excursion using the XCO library. In this example, tranformation programs are retrieved. - "A filter is applied. Because of a filter that is applied, only the ABAP cheat sheet - "transformation programs are returned. - - DATA(filter) = xco_cp_abap_repository=>object_name->get_filter( - xco_cp_abap_sql=>constraint->contains_pattern( 'ZDEMO_ABAP_%' ) ). - - DATA(filtered_transformations) = xco_cp_abap_repository=>objects->xslt->where( VALUE #( ( filter ) - ) )->in( xco_cp_abap=>repository )->get( ). - - IF filtered_transformations IS NOT INITIAL. - TYPES cst TYPE TABLE OF sxco_tf_object_name WITH EMPTY KEY. - DATA(cheat_sheet_transformations) = VALUE cst( FOR tr IN filtered_transformations ( tr->name ) ). - out->write( cheat_sheet_transformations ). - out->write( |\n| ). - out->write( `The code contains an implementation that gets all the transformations in the system.` ). - out->write( `You can check the content of the variable in the debugger. Among the transformations is the predefined identity transformation ID.` ). - ENDIF. - - "Getting all transformations in the system - "You can check the table content in the debugger. - DATA(all_transformations) = xco_cp_abap_repository=>objects->xslt->all->in( xco_cp_abap=>repository )->get( ). - IF all_transformations IS NOT INITIAL. - DATA(all_transformations_in_system) = VALUE cst( FOR tr IN all_transformations ( tr->name ) ). - ENDIF. - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `10) Transforming XML to XML Using XSLT` ) ). - "In this example, XML is transformed to XML. For this purpose, a simple XSLT - "program does the following: - "- All nodes and attributes are copied from the source XML to the target XML - " without any changes. - "- A match on two elements is performed. If matched, two new elements are created - " in the target XML. In this operation, calculations are carried out (free seats - " and the occupancy rate based on the values of maximum and occupied seats). - "Note: - "- The element names in the demo XML data are capitalized on purpose because the - " XML data is used in another example that uses the asXML format. In deserializations - " of XML data to ABAP data, the elements that are deserialized must be capitalized - " so that they can be identified. - "Tranformations are performed using CALL TRANSFORMATION statements. - - "Creating demo XML data to be used in the example - TRY. - DATA(xml_flights) = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( - `` && - ` ` && - ` AA` && - ` 17` && - ` 385` && - ` 369` && - ` ` && - ` ` && - ` LH` && - ` 400` && - ` 330` && - ` 319` && - ` ` && - `` ). - CATCH cx_sy_conversion_codepage. - ENDTRY. - - DATA xml_a TYPE xstring. - - CALL TRANSFORMATION zdemo_abap_xslt_flights - SOURCE XML xml_flights - RESULT XML xml_a. - - DATA(conv_xml_a) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_a ) ). - out->write( conv_xml_a ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `11) Transforming ABAP to XML Using XSLT` ) ). - "In the example, data entries are retrieved from a database table. Appropriate names for the - "table columns are used with the AS addition so that the transformation can be carried - "out based on the selected data. - "Note: The resulting XML has the asXML format. - - SELECT carrid AS carrier, - connid AS connectionid, - seatsmax AS maxSeats, - seatsocc AS occSeats - FROM zdemo_abap_fli - WHERE carrid = 'AZ' - INTO TABLE @DATA(fli_itab) - UP TO 2 ROWS. - - DATA xml_b TYPE xstring. - - CALL TRANSFORMATION zdemo_abap_xslt_flights - SOURCE flights = fli_itab - RESULT XML xml_b. - - DATA(conv_xml_b) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_b ) ). - out->write( conv_xml_b ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `12) ABAP <-> XML using Simple Transformations (1)` ) ). - "The following simple transformation examples transform ABAP to XML and back. The - "Simple Transformation is implemented in a way to transform to the HTML format. - "This example transforms string tables to html. - - DATA(string_table_a) = VALUE string_table( ( `abc` ) ( `def` ) ( `ghi` ) ). - - DATA xml_c TYPE xstring. - - "ABAP -> XML - CALL TRANSFORMATION zdemo_abap_st_strtab_html - SOURCE string_table = string_table_a - RESULT XML xml_c. - - DATA(conv_xml_c) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_c ) ). - out->write( `ABAP -> XML` ). - out->write( conv_xml_c ). - out->write( |\n| ). - - "XML -> ABAP - DATA string_table_b TYPE string_table. - CALL TRANSFORMATION zdemo_abap_st_strtab_html - SOURCE XML xml_c - RESULT string_table = string_table_b. - - out->write( `XML -> ABAP` ). - out->write( string_table_b ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `13) ABAP <-> XML using Simple Transformations (2)` ) ). - "In this example, an internal table is transformed to XML using Simple Transformation. - "HTML tags are inserted into the XML data as literals. - - SELECT carrid, carrname, currcode, url - FROM zdemo_abap_carr - INTO TABLE @DATA(carr_tab_a) - UP TO 2 ROWS. - - "ABAP -> XML - DATA str_a TYPE string. - - "The following CALL TRANSFORMATION statement includes the OPTIONS - "addition. In this example, the XML header should not be added. - "So, you can take the resulting html and test it in an HTML viewer. - - CALL TRANSFORMATION zdemo_abap_st_carriers_html - SOURCE carrier_info = carr_tab_a - RESULT XML str_a - OPTIONS xml_header = 'NO'. - - out->write( `ABAP -> XML` ). - out->write( format( str_a ) ). - out->write( |\n| ). - - "XML -> ABAP - DATA carr_tab_b LIKE carr_tab_a. - - CALL TRANSFORMATION zdemo_abap_st_carriers_html - SOURCE XML str_a - RESULT carrier_info = carr_tab_b. - - out->write( `XML -> ABAP` ). - out->write( carr_tab_b ). - -*********************************************************************** - - out->write( zcl_demo_abap_aux=>heading( `ABAP <-> XML using XSLT (Using the Predefined Identity Transformation ID)` ) ). - "The following examples demonstrate serializations (ABAP to XML) and deserializations (XML to ABAP) - "using the predefined identity transformation ID. - "Note: In doing so, ABAP data is transformed to their asXML representations that can be used as an - " intermediate format and which define a mapping between ABAP data and XML. - - out->write( |14) Elementary type\n\n| ). - "The example uses type string as an elementary type. - - "ABAP -> XML - DATA xml_d TYPE xstring. - DATA(str_b) = `This is some string.`. - - CALL TRANSFORMATION id SOURCE txt = str_b - RESULT XML xml_d. - - DATA(conv_xml_d) = cl_abap_conv_codepage=>create_in( )->convert( xml_d ). - out->write( `ABAP -> XML` ). - out->write( format( conv_xml_d ) ). - out->write( |\n| ). - - "XML -> ABAP - DATA str_c TYPE string. - CALL TRANSFORMATION id SOURCE XML xml_d - RESULT txt = str_c. - - out->write( `XML -> ABAP` ). - out->write( str_c ). - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `15) Structures` ) ). - - SELECT SINGLE carrid, carrname, currcode, url - FROM zdemo_abap_carr - WHERE carrid = 'LH' - INTO @DATA(carr_struc_a). - - "ABAP -> XML - DATA xml_e TYPE xstring. - CALL TRANSFORMATION id SOURCE structure = carr_struc_a - RESULT XML xml_e. - - DATA(conv_xml_e) = cl_abap_conv_codepage=>create_in( )->convert( xml_e ). - out->write( `ABAP -> XML` ). - out->write( format( conv_xml_e ) ). - out->write( |\n| ). - - "XML -> ABAP - DATA carr_struc_b LIKE carr_struc_a. - CALL TRANSFORMATION id SOURCE XML xml_e - RESULT structure = carr_struc_b. - - out->write( `XML -> ABAP` ). - out->write( carr_struc_b ). - out->write( |\n| ). - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `16) Internal tables` ) ). - - SELECT carrid, connid, fldate, price, currency - FROM zdemo_abap_fli - WHERE carrid = 'JL' - INTO TABLE @DATA(fli_tab_a) - UP TO 2 ROWS. - - "ABAP -> XML - DATA xml_f TYPE xstring. - CALL TRANSFORMATION id SOURCE itab = fli_tab_a - RESULT XML xml_f. - - DATA(conv_xml_f) = cl_abap_conv_codepage=>create_in( )->convert( xml_f ). - out->write( `ABAP -> XML` ). - out->write( format( conv_xml_f ) ). - out->write( |\n| ). - - "XML -> ABAP - DATA fli_tab_b LIKE fli_tab_a. - CALL TRANSFORMATION id SOURCE XML xml_f - RESULT itab = fli_tab_b. - - out->write( `XML -> ABAP` ). - out->write( fli_tab_b ). - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `17) Data References` ) ). - - DATA(dref_a) = NEW i( 123 ). - - "ABAP -> XML - DATA xml_g TYPE xstring. - CALL TRANSFORMATION id SOURCE dref = dref_a - RESULT XML xml_g. - - DATA(conv_xml_g) = cl_abap_conv_codepage=>create_in( )->convert( xml_g ). - - out->write( `ABAP -> XML` ). - out->write( format( conv_xml_g ) ). - out->write( |\n| ). - - "XML -> ABAP - DATA dref_b LIKE dref_a. - CALL TRANSFORMATION id SOURCE XML xml_g - RESULT dref = dref_b. - - out->write( `XML -> ABAP` ). - out->write( dref_b->* ). - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `18) Object References` ) ). - "The following example demonstrates the serialization and deserialization of - "instances of classes (objects). For example, to serialize instance attributes, - "classes must implement the if_serializable_object interface. By default, all instance - "attributes of an object are serialized, regardless of their visibility section. - "However, you can change this behavior using the serialize_helper and deserialize_helper - "instance methods. As a result of the transformation, you get an asXML representation of - "the object. - "The example is implemented as follows: - "- The class implements the if_serializable_object interface. - "- There are 4 instance attributes of type string. - "- There are two instance methods: - " - One method concatenates two of the strings and assigns the resulting string to - " another string. - " - Another method concatenates two strings and converts the string to lowercase. - " The result is assigned to another string. - "- Serialization preserves instance attribute values in the asXML representation of the - " object. - "- During deserialization, the instance attribute values are transformed back and can - " be accessed. - "- The example includes the implementation of the serialize_helper and deserialize_helper - " instance methods. Without implementation, all instance attributes would be - " serialized/deserialized. The sample implementation limits serialization/deserialization. - " The fourth instance attribute, which is converted to a lowercase string when calling the - " method, is not part of the serialization/deserialization. See the implementation of the - " serialize_helper and deserialize_helper instance methods. They explicitly specify what - " to serialize and deserialize. - "- Note: For each output parameter of the serialize_helper method, you must specify an - " identically-named input parameter of the deserialize_helper method. The parameters must - " have the same type. - - DATA(oref_a) = NEW zcl_demo_abap_xml_json( ). - oref_a->attr_string_a = `AB`. - oref_a->attr_string_b = `AP`. - oref_a->concatenate_string( ). - oref_a->lowercase_string( ). - - out->write( `Value of instance attribute attr_lowercase_str for the created instance (before serialization/deserialization):` ). - out->write( oref_a->attr_lowercase_str ). - out->write( |\n| ). - - "ABAP -> XML - DATA xml_oref_a TYPE xstring. - CALL TRANSFORMATION id SOURCE oref = oref_a - RESULT XML xml_oref_a. - - DATA(conv_xml_oref_a) = cl_abap_conv_codepage=>create_in( )->convert( xml_oref_a ). - - out->write( `ABAP -> XML` ). - out->write( format( conv_xml_oref_a ) ). - out->write( |\n| ). - - "XML -> ABAP - DATA oref_b LIKE oref_a. - CALL TRANSFORMATION id SOURCE XML xml_oref_a - RESULT oref = oref_b. - - out->write( `XML -> ABAP` ). - out->write( oref_b->attr_string_a ). - out->write( oref_b->attr_string_b ). - out->write( oref_b->attr_concat_string ). - out->write( |\n| ). - IF oref_b->attr_lowercase_str IS INITIAL. - out->write( `The instance attribute attr_lowercase_str is initial. The serialization/deserialization is restricted.` ). - ENDIF. - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `19) CALL TRANSFORMATION Syntax: Specifying Transformations` ) ). - "As already covered in the examples above, transformations are specified after - "CALL TRANSFORMATION. They are either ... - - "... XSLT programs - CALL TRANSFORMATION zdemo_abap_st_carriers_html SOURCE carrier_info = carr_tab_a - RESULT XML str_a. - - "... predefined identity transformations - CALL TRANSFORMATION id SOURCE dref = dref_a - RESULT XML xml_g. - - "... dynamically specified transformation (valid for both XSLT and ST). In the examples above, - "the transformation is specified statically. Dynamic specifications are possible. A - "character-like data object in uppercase letters is expected in parentheses (either a named - "or unnamed data objects). - CALL TRANSFORMATION ('ID') SOURCE dref = dref_a - RESULT XML xml_g. - - "If a dynamically specified transformation is not found, an exception of the class - "CX_INVALID_TRANSFORMATION is raied. The example uses a named data object. - DATA(notr) = 'NON_EXISTENT_TRANSFORMATION'. - TRY. - CALL TRANSFORMATION (notr) SOURCE dref = dref_a - RESULT XML xml_g. - CATCH cx_invalid_transformation INTO DATA(error_non). - out->write( error_non->get_text( ) ). - ENDTRY. - - "... Simple Transformation - CALL TRANSFORMATION zdemo_abap_st_carriers_html SOURCE XML str_a - RESULT carrier_info = carr_tab_b. - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `20) CALL TRANSFORMATION Syntax: Sources of Transformations` ) ). - "The following examples use the predefined identity transformation ID. - "The result is asXML data and stored in a variable of type xstring. - "Multiple options and variants are possible. The examples cover a selection. - - out->write( `********** Source options for transforming XML data **********` ). - out->write( |\n| ). - - "Source: XML data in a data object of type string. It is implicitly transformed to - "XML in this case. - "Note: It must have character-like XML data in XML 1.0 format. - DATA(str_d) = `Hello world`. - DATA xml_h TYPE xstring. - CALL TRANSFORMATION id SOURCE XML str_d - RESULT XML xml_h. - - DATA(conv_xml_h) = cl_abap_conv_codepage=>create_in( )->convert( xml_h ). - - out->write( `Source: XML data in data object of type string` ). - out->write( format( conv_xml_h ) ). - out->write( |\n| ). - - "Source: XML data in a data object of type xstring - DATA(xml_i) = cl_abap_conv_codepage=>create_out( )->convert( `Hi ABAP` ). - DATA xml_j TYPE xstring. - CALL TRANSFORMATION id SOURCE XML xml_i - RESULT XML xml_j. - - DATA(conv_xml_j) = cl_abap_conv_codepage=>create_in( )->convert( xml_j ). - out->write( `Source: XML data in a data object of type xstring` ). - out->write( format( conv_xml_j ) ). - out->write( |\n| ). - - "Source: Standard table with character-like data type - DATA(stdtab_clike) = VALUE c50_tab_type( ( 'Hi' ) ( 'ABAP' ) ). - DATA xml_k TYPE xstring. - CALL TRANSFORMATION id SOURCE tab = stdtab_clike - RESULT XML xml_k. - - DATA(conv_xml_k) = cl_abap_conv_codepage=>create_in( )->convert( xml_k ). - out->write( `Source: Standard table with character-like data type` ). - out->write( format( conv_xml_k ) ). - out->write( |\n| ). - - "Source: Standard table with byte-like data type - DATA(stdtab_bytelike) = VALUE x30_tab_type( ( cl_abap_conv_codepage=>create_out( )->convert( `Hello` ) ) - ( cl_abap_conv_codepage=>create_out( )->convert( `ABAP` ) ) ). - DATA xml_l TYPE xstring. - CALL TRANSFORMATION id SOURCE xtab = stdtab_bytelike - RESULT XML xml_l. - - DATA(conv_xml_l) = cl_abap_conv_codepage=>create_in( )->convert( xml_l ). - out->write( `Source: Standard table with byte-like data type` ). - out->write( format( conv_xml_l ) ). - out->write( |\n| ). - - "Furthermore, some references to iXML and sXML libraries are possible. - "The following example covers sXML (an interface reference variable of type if_sxml_reader). - DATA(sxml_reader) = cl_sxml_string_reader=>create( xml_h ). - DATA xml_m TYPE xstring. - CALL TRANSFORMATION id SOURCE XML sxml_reader - RESULT XML xml_m. - - DATA(conv_xml_m) = cl_abap_conv_codepage=>create_in( )->convert( xml_m ). - out->write( `Source: Interface reference variable with TYPE REF TO if_sxml_reader` ). - out->write( format( conv_xml_m ) ). - out->write( |\n| ). - - out->write( `********** Source options for transforming ABAP data **********` ). - out->write( |\n| ). - "Using ... SOURCE ... without specifying XML - "One or multiple ABAP data objects can be specified. - - "Source: Data object of type string - "elem stands for the name of an XML element. - DATA(str_e) = `abcdef`. - DATA xml_n TYPE xstring. - CALL TRANSFORMATION id SOURCE elem = str_e - RESULT XML xml_n. - - DATA(conv_xml_n) = cl_abap_conv_codepage=>create_in( )->convert( xml_n ). - out->write( `Source: Character string in data object of type string` ). - out->write( format( conv_xml_n ) ). - out->write( |\n| ). - - "Source: Data object of type string - DATA(str_f) = `some string`. - DATA xml_o TYPE xstring. - CALL TRANSFORMATION id SOURCE txt = str_f - RESULT XML xml_o. - - DATA(conv_xml_o) = cl_abap_conv_codepage=>create_in( )->convert( xml_o ). - out->write( `Source: Character string of type string` ). - out->write( format( conv_xml_o ) ). - out->write( |\n| ). - - "Source: Multiple data objects - DATA a_i TYPE i VALUE 123. - DATA b_str TYPE string VALUE `Hallo`. - DATA c_p TYPE p LENGTH 5 DECIMALS 2 VALUE `4.56`. - DATA xml_p TYPE xstring. - - CALL TRANSFORMATION id SOURCE x = a_i - y = b_str - z = c_p - RESULT XML xml_p. - - DATA(conv_xml_p) = cl_abap_conv_codepage=>create_in( )->convert( xml_p ). - out->write( `Source: Multiple ABAP data objects in a static parameter list` ). - out->write( format( conv_xml_p ) ). - out->write( |\n| ). - - "Source: Dynamic specification of ABAP data objects in an internal table of - "type abap_trans_srcbind_tab - DATA(srctab) = VALUE abap_trans_srcbind_tab( - ( name = 'X' value = REF #( a_i ) ) - ( name = 'Y' value = REF #( b_str ) ) - ( name = 'Z' value = REF #( c_p ) ) ). - DATA xml_q TYPE xstring. - - CALL TRANSFORMATION id SOURCE (srctab) - RESULT XML xml_q. - - DATA(conv_xml_q) = cl_abap_conv_codepage=>create_in( )->convert( xml_q ). - out->write( `Source: Multiple ABAP data objects in an internal table` ). - out->write( format( conv_xml_q ) ). - -************************************************************************* - - out->write( zcl_demo_abap_aux=>heading( `21) CALL TRANSFORMATION Syntax: Results of Transformations` ) ). - "As in the examples above, the predefined identity transformation is used here. - - "Creating demo XML data to be used in the example as the source. - DATA(demo_xml) = cl_abap_conv_codepage=>create_out( )->convert( `Hi ABAP` ). - - out->write( `********** Result options for transforming to XML data ********** ` ). - out->write( |\n| ). - - "Result: Data object of type string - "The example uses the OPTIONS addition. The XML header should not be added. - DATA str_g TYPE string. - CALL TRANSFORMATION id SOURCE XML demo_xml - RESULT XML str_g - OPTIONS xml_header = 'NO'. - - out->write( `Result: Data object of type string` ). - out->write( str_g ). - out->write( |\n| ). - - "Data object of type xstring - DATA xml_r TYPE xstring. - CALL TRANSFORMATION id SOURCE XML demo_xml - RESULT XML xml_r. - - DATA(conv_xml_r) = cl_abap_conv_codepage=>create_in( )->convert( xml_r ). - out->write( `Result: Data object of type xstring` ). - out->write( format( conv_xml_r ) ). - out->write( |\n| ). - - "Data object declared inline (e.g. DATA(a) or FINAL(b)), which has then the type xstring - CALL TRANSFORMATION id SOURCE XML demo_xml - RESULT XML DATA(xml_s). - - DATA(conv_xml_s) = cl_abap_conv_codepage=>create_in( )->convert( xml_s ). - out->write( `Result: Data object declared inline (type xstring)` ). - out->write( format( conv_xml_s ) ). - out->write( |\n| ). - - "Standard table with character-like line type - DATA stdtab_clike_b TYPE c50_tab_type. - CALL TRANSFORMATION id SOURCE XML demo_xml - RESULT XML stdtab_clike_b - OPTIONS xml_header = 'NO'. - - out->write( `Result: Standard table with character-like line type` ). - out->write( stdtab_clike_b ). - out->write( |\n| ). - - "Standard table with byte-like line type - DATA stdtab_bytelike_b TYPE x30_tab_type. - CALL TRANSFORMATION id SOURCE XML demo_xml - RESULT XML stdtab_bytelike_b. - - out->write( `Result: Standard table with byte-like line type` ). - out->write( stdtab_bytelike_b ). - out->write( |\n| ). - - "Furthermore, some references to iXML and sXML libraries are possible. - "The following example covers sXML (an object reference variable of type ref to cl_sxml_string_writer) - "Other types are possible, for example JSON writers. - DATA(writer4tr) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 ). - CALL TRANSFORMATION id SOURCE XML demo_xml - RESULT XML writer4tr. - - DATA(xml_t) = writer4tr->get_output( ). - DATA(conv_xml_t) = cl_abap_conv_codepage=>create_in( )->convert( xml_t ). - out->write( `Result: Object reference variable with type ref to cl_sxml_string_writer` ). - out->write( format( conv_xml_t ) ). - out->write( |\n| ). - - out->write( `********** Result options for transforming to ABAP data **********` ). - out->write( |\n| ). - - "Similar to above, multiple ABAP data objects can be specified as a static parameter list. - "Here, the example from above is used. The tranformation is performed the other way round. - DATA d_i LIKE a_i. - DATA e_str LIKE b_str. - DATA f_p LIKE c_p. - - CALL TRANSFORMATION id SOURCE XML xml_p - RESULT x = d_i - y = e_str - z = f_p. - - out->write( `Result: Multiple ABAP data objects in a static parameter list` ). - out->write( d_i ). - out->write( e_str ). - out->write( f_p ). - out->write( |\n| ). - - "Specifying an internal table of type abap_trans_resbind_tab - DATA g_i LIKE a_i. - DATA h_str LIKE b_str. - DATA i_p LIKE c_p. - - "Note: Only bound parts are deserialized, i.e. the result table must be - "filled accordingly. - DATA(restab) = VALUE abap_trans_resbind_tab( - ( name = 'X' value = REF #( d_i ) ) - ( name = 'Y' value = REF #( e_str ) ) - ( name = 'Z' value = REF #( f_p ) ) ). - - CALL TRANSFORMATION id SOURCE XML xml_q - RESULT (restab). - - out->write( `Result: Multiple ABAP data objects in an internal table` ). - out->write( restab ). - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `22) Dealing with JSON Data` ) ). - "Note: When the identity transformation ID is used, the format is asJSON. - - "Elementary type - DATA str_h TYPE string VALUE `Hello`. - "ABAP -> JSON - "Creating a JSON writer - DATA(json_wr_a) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). - - CALL TRANSFORMATION id SOURCE hi = str_h - RESULT XML json_wr_a. - - DATA(json_a) = cl_abap_conv_codepage=>create_in( )->convert( json_wr_a->get_output( ) ). - - out->write( `ABAP -> JSON: Elementary type` ). - out->write( json_a ). - out->write( |\n| ). - - "JSON -> ABAP - DATA str_i TYPE string. - "Note: CALL TRANSFORMATION handles JSON sources implicitly. - CALL TRANSFORMATION id SOURCE XML json_a - RESULT hi = str_i. - - out->write( `JSON -> ABAP: Elementary type` ). - out->write( str_i ). - out->write( |\n| ). - - "Structure - SELECT SINGLE carrid, carrname, currcode, url - FROM zdemo_abap_carr - WHERE carrid = 'AZ' - INTO @DATA(carr_struc_c). - - "ABAP -> JSON - DATA(json_wr_b) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). - - CALL TRANSFORMATION id SOURCE structure = carr_struc_c - RESULT XML json_wr_b. - - DATA(json_b) = cl_abap_conv_codepage=>create_in( )->convert( json_wr_b->get_output( ) ). - out->write( `ABAP -> JSON: Structure` ). - out->write( json_b ). - out->write( |\n| ). - - "JSON -> ABAP - DATA carr_struc_d LIKE carr_struc_c. - CALL TRANSFORMATION id SOURCE XML json_b - RESULT structure = carr_struc_d. - - out->write( `JSON -> ABAP: Structure` ). - out->write( carr_struc_d ). - out->write( |\n| ). - - "Internal table - SELECT carrid, carrname, currcode, url - FROM zdemo_abap_carr - INTO TABLE @DATA(carr_tab_c) - UP TO 2 ROWS. - - "ABAP -> JSON - "This examples uses a cast to get access to further methods. - DATA(json_wr_c) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). - DATA(json_wr_cast) = CAST if_sxml_writer( json_wr_c ). - - "With the following method calls, the result is formatted. - json_wr_cast->set_option( option = if_sxml_writer=>co_opt_linebreaks ). - json_wr_cast->set_option( option = if_sxml_writer=>co_opt_indent ). - - CALL TRANSFORMATION id SOURCE itab = carr_tab_c - RESULT XML json_wr_c. - - DATA(json_c) = cl_abap_conv_codepage=>create_in( )->convert( json_wr_c->get_output( ) ). - out->write( `ABAP -> JSON: Internal table` ). - out->write( json_c ). - out->write( |\n| ). - - "JSON -> ABAP - DATA carr_tab_d LIKE carr_tab_c. - - CALL TRANSFORMATION id SOURCE XML json_c - RESULT itab = carr_tab_d. - - out->write( `JSON -> ABAP: Internal table` ). - out->write( carr_tab_d ). - out->write( |\n| ). - - "JSON -> XML - DATA(str_j) = - `{` && - `"flights": [` && - ` {` && - ` "carrier": "LH",` && - ` "connectionid": "400",` && - ` "from": "Frankfurt",` && - ` "to": "Berlin"` && - ` },` && - ` {` && - ` "carrier": "DL",` && - ` "connectionid": "400",` && - ` "from": "San Francisco",` && - ` "to": "New York"` && - ` }` && - `]` && - `}`. - - DATA(json_d) = cl_abap_conv_codepage=>create_out( )->convert( str_j ). - DATA(json_wr_d) = cl_sxml_string_reader=>create( json_d ). - DATA json2xml_ct TYPE xstring. - - "JSON -> XML using CALL TRANSFORMATION - CALL TRANSFORMATION id SOURCE XML json_wr_d - RESULT XML json2xml_ct. - - DATA(conv_json2xml_ct) = cl_abap_conv_codepage=>create_in( )->convert( json2xml_ct ). - - out->write( `JSON -> XML using CALL TRANSFORMATION` ). - out->write( format( conv_json2xml_ct ) ). - out->write( |\n| ). - - "JSON -> XML using sXML - DATA(reader_a) = cl_sxml_string_reader=>create( cl_abap_conv_codepage=>create_out( - )->convert( str_j ) ). - "XML writer (note the type specification in contrast to the previous examples) - DATA(xml_wr) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 ). - - TRY. - reader_a->next_node( ). - "The reader parses the data in one go by calling the SKIP_NODE method. - "The data is passed to an XML writer. - reader_a->skip_node( xml_wr ). - CATCH cx_sxml_parse_error INTO DATA(err_pa). - out->write( err_pa->get_text( ) ). - ENDTRY. - - DATA(json2xml_sxml) = cl_abap_conv_codepage=>create_in( )->convert( xml_wr->get_output( ) ). - out->write( `JSON -> XML using sXML` ). - out->write( format( json2xml_sxml ) ). - out->write( |\n| ). - - "XML -> JSON using CALL TRANSFORMATION - DATA(json_wr_f) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). - - CALL TRANSFORMATION id SOURCE XML json2xml_sxml - RESULT XML json_wr_f. - - DATA(xml2json_ct) = cl_abap_conv_codepage=>create_in( )->convert( json_wr_f->get_output( ) ). - out->write( `XML -> JSON using CALL TRANSFORMATION` ). - out->write( xml2json_ct ). - out->write( |\n| ). - - "XML -> JSON using sXML - DATA(reader_b) = cl_sxml_string_reader=>create( cl_abap_conv_codepage=>create_out( )->convert( xml2json_ct ) ). - DATA(json_wr) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). - - TRY. - reader_b->next_node( ). - reader_b->skip_node( json_wr ). - CATCH cx_sxml_parse_error INTO DATA(err_xj). - out->write( err_xj->get_text( ) ). - ENDTRY. - - DATA(xml2json_sxml) = cl_abap_conv_codepage=>create_in( )->convert( json_wr->get_output( ) ). - out->write( `XML -> JSON using sXML` ). - out->write( xml2json_sxml ). - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `23) XCO Classes for JSON` ) ). - "Note: Unlike above, the following snippets do not work with asJSON as intermediate - "format. - - DATA: BEGIN OF carrier_struc, - carrier_id TYPE c length 3, - connection_id TYPE n length 4, - city_from TYPE c length 20, - city_to TYPE c length 20, - END OF carrier_struc. - - DATA carriers_tab like TABLE OF carrier_struc WITH EMPTY KEY. - - carrier_struc = VALUE #( carrier_id = 'AA' connection_id = '17' city_from = 'New York' city_to = 'San Francisco' ). - carriers_tab = VALUE #( ( carrier_id = 'AZ' connection_id = '788' city_from = 'Rome' city_to = 'Tokyo' ) - ( carrier_id = 'JL' connection_id = '408' city_from = 'Frankfurt' city_to = 'Tokyo' ) - ( carrier_id = 'LH' connection_id = '2402' city_from = 'Frankfurt' city_to = 'Berlin' ) ). - - "ABAP (structure) -> JSON using XCO - DATA(struc2json_xco) = xco_cp_json=>data->from_abap( carrier_struc )->to_string( ). - out->write( `ABAP (structure) -> JSON using XCO` ). - out->write( format( input = struc2json_xco xml = abap_false ) ). - out->write( |\n| ). - - "ABAP (internal table) -> JSON using XCO - DATA(itab2json_xco) = xco_cp_json=>data->from_abap( carriers_tab )->to_string( ). - out->write( `ABAP (internal table) -> JSON using XCO` ). - out->write( format( input = itab2json_xco xml = abap_false ) ). - out->write( |\n| ). - - "JSON -> ABAP (structure) using XCO - DATA json2struc_xco LIKE carrier_struc. - xco_cp_json=>data->from_string( struc2json_xco )->write_to( REF #( json2struc_xco ) ). - out->write( `JSON -> ABAP (structure) using XCO` ). - out->write( json2struc_xco ). - out->write( |\n| ). - - "JSON -> ABAP (internal table) using XCO - DATA json2itab_xco LIKE carriers_tab. - xco_cp_json=>data->from_string( itab2json_xco )->write_to( REF #( json2itab_xco ) ). - out->write( `JSON -> ABAP (internal table) using XCO` ). - out->write( json2itab_xco ). - out->write( |\n| ). - - "Creating JSON using XCO - "Check out more methods that offer more options to build the JSON by clicking - "CTRL + Space after '->' in ADT. - DATA(json_builder_xco) = xco_cp_json=>data->builder( ). - json_builder_xco->begin_object( - )->add_member( 'CarrierId' )->add_string( 'DL' - )->add_member( 'ConnectionId' )->add_string( '1984' - )->add_member( 'CityFrom' )->add_string( 'San Francisco' - )->add_member( 'CityTo' )->add_string( 'New York' - )->end_object( ). - - "Getting JSON data - DATA(json_created_xco) = json_builder_xco->get_data( )->to_string( ). - - out->write( `Creating JSON using XCO` ). - out->write( format( input = json_created_xco xml = abap_false ) ). - out->write( |\n| ). - - "Transforming the created JSON to ABAP (structure) - "Note: The JSON was intentionally created without the underscores in the - "name to demonstrate the 'apply' method. The following example demonstrates - "a transformation of camel case and underscore notation. As above, check out - "more options by clicking CTRL + Space after '...transformation->'. - CLEAR json2struc_xco. - xco_cp_json=>data->from_string( json_created_xco )->apply( VALUE #( - ( xco_cp_json=>transformation->pascal_case_to_underscore ) ) )->write_to( REF #( json2struc_xco ) ). - - out->write( `JSON -> ABAP (structure) using XCO demonstrating the apply method` ). - out->write( json2struc_xco ). - -************************************************************************ - - out->write( zcl_demo_abap_aux=>heading( `24) Excursion: Compressing and Decompressing Binary Data` ) ). - "You may want to process or store binary data. The data can be very large. - "You can compress the data in gzip format and decompress it for further processing using - "the cl_abap_gzip class. Check out appropriate exceptions to be caught. The simple example - "just specifies cx_root. See the class documentation for more information. - "This example uses a data object of type xstring from a previous example. - - "Compressing binary data - DATA xstr_comp TYPE xstring. - TRY. - cl_abap_gzip=>compress_binary( EXPORTING raw_in = xml_oref_a - IMPORTING gzip_out = xstr_comp ). - CATCH cx_root INTO DATA(error_comp). - out->write( error_comp->get_text( ) ). - ENDTRY. - - "Decompressing binary data - DATA xstr_decomp TYPE xstring. - TRY. - cl_abap_gzip=>decompress_binary( EXPORTING gzip_in = xstr_comp - IMPORTING raw_out = xstr_decomp ). - - CATCH cx_root INTO DATA(error_decomp). - out->write( error_decomp->get_text( ) ). - ENDTRY. - - "Checking the xstring length of the variables used and comparing the result - DATA(strlen_original_xstring) = xstrlen( xml_oref_a ). - out->write( |Length of original binary data object: { strlen_original_xstring }| ). - DATA(strlen_comp) = xstrlen( xstr_comp ). - out->write( |Length of compressed binary data object: { strlen_comp }| ). - DATA(strlen_decomp) = xstrlen( xstr_decomp ). - out->write( |Length of decompressed binary data object: { strlen_decomp }| ). - IF xml_oref_a = xstr_decomp. - out->write( `The decompressed binary data object has the same value as the original binary data object.` ). - ENDIF. - ENDMETHOD. - METHOD format. - TRY. - DATA(xstr) = cl_abap_conv_codepage=>create_out( )->convert( input ). - DATA(reader) = cl_sxml_string_reader=>create( xstr ). - DATA(writer) = CAST if_sxml_writer( cl_sxml_string_writer=>create( - type = COND #( WHEN xml = abap_true THEN if_sxml=>co_xt_xml10 ELSE if_sxml=>co_xt_json ) ) ). - writer->set_option( option = if_sxml_writer=>co_opt_linebreaks ). - writer->set_option( option = if_sxml_writer=>co_opt_indent ). - reader->next_node( ). - reader->skip_node( writer ). - string = cl_abap_conv_codepage=>create_in( )->convert( CAST cl_sxml_string_writer( writer )->get_output( ) ). - CATCH cx_root. - string = `Issue when formatting.`. - ENDTRY. - - ENDMETHOD. - - METHOD class_constructor. - "Filling demo database tables. - zcl_demo_abap_aux=>fill_dbtabs( ). - ENDMETHOD. - - METHOD concatenate_string. - attr_concat_string = attr_string_a && attr_string_b. - ENDMETHOD. - - METHOD deserialize_helper. - me->attr_string_a = attr_string_a. - me->attr_string_b = attr_string_b. - me->attr_concat_string = attr_concat_string. - ENDMETHOD. - - METHOD serialize_helper. - attr_string_a = me->attr_string_a. - attr_string_b = me->attr_string_b. - attr_concat_string = me->attr_concat_string. - ENDMETHOD. - - METHOD lowercase_string. - attr_lowercase_str = to_lower( attr_string_a && attr_string_b ). - ENDMETHOD. - +*********************************************************************** +* +* ABAP cheat sheet: Working with XML and JSON in ABAP +* +* -------------------------- PURPOSE ---------------------------------- +* - Example that demonstrates working with XML and JSON in ABAP. +* - The following topics are covered:* +* - Processing XML using class libraries (iXML, sXML) +* - XML Transformations using XSLT and Simple Transformations +* - CALL TRANSFORMATION syntax +* - Dealing with JSON data, XCO classes for JSON +* - Excursions: Converting string <-> xstring, compressing and +* decompressing binary data +* +* ----------------------- GETTING STARTED ----------------------------- +* - Open the class with the ABAP development tools for Eclipse (ADT). +* - Choose F9 to run the class. +* - Check the console output. +* - To understand the context and the ABAP syntax used, refer to the +* notes included in the class as comments or refer to the respective +* topic in the ABAP Keyword Documentation. +* - Due to the amount of console output, the examples contain numbers +* (e.g. 1) ..., 2) ..., 3) ...) for the individual example sections. +* Also, the variable name is displayed in most cases. So to find +* the relevant output in the console easier and faster, just search +* for the number/variable name in the console (CTRL+F in the console) +* or use the debugger. +* +* ----------------------------- NOTE ----------------------------------- +* The code presented in this class is intended only to support the ABAP +* cheat sheets. It is not intended for direct use in a production system +* environment. The code examples in the ABAP cheat sheets are primarily +* intended to provide a better explanation and visualization of the +* syntax and semantics of ABAP statements, not to solve concrete +* programming tasks. For production application programs, you should +* always work out your own solution for each individual case. There is +* no guarantee for the correctness or completeness of the code. +* Furthermore, there is no legal responsibility or liability for any +* errors or their consequences that may occur when using the the example +* code. +* +*********************************************************************** +"!

ABAP cheat sheet: Working with XML and JSON in ABAP

+"! Example that demonstrates working with XML and JSON in ABAP..
Choose F9 in ADT to run the class. +CLASS zcl_demo_abap_xml_json DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + INTERFACES: if_oo_adt_classrun, + "This interface is implemented for serializing and + "deserialzing instances of classes (objects). + if_serializable_object. + CLASS-METHODS class_constructor. + + PROTECTED SECTION. + PRIVATE SECTION. + CLASS-METHODS format IMPORTING input TYPE data + xml TYPE abap_bool DEFAULT abap_true + RETURNING VALUE(string) TYPE string. + TYPES c50 TYPE c LENGTH 50. + TYPES c50_tab_type TYPE TABLE OF c50 WITH EMPTY KEY. + TYPES x30 TYPE x LENGTH 30. + TYPES x30_tab_type TYPE TABLE OF x30 WITH EMPTY KEY. + + "The following instance attribues and methods are used for serializing and + "deserialzing instances of classes (objects) + DATA: attr_string_a TYPE string, + attr_string_b TYPE string, + attr_concat_string TYPE string, + attr_lowercase_str TYPE string. + METHODS: concatenate_string, + lowercase_string, + "The following method can only have output parameters. + "For each output parameter of the serialize_helper method, you must specify + "an identically named input parameter of the deserialize_helper method + "with the same type. + serialize_helper EXPORTING attr_string_a TYPE string + attr_string_b TYPE string + attr_concat_string TYPE string, + "This method can only have input parameters. + deserialize_helper IMPORTING attr_string_a TYPE string + attr_string_b TYPE string + attr_concat_string TYPE string. +ENDCLASS. + + + +CLASS zcl_demo_abap_xml_json IMPLEMENTATION. + + METHOD if_oo_adt_classrun~main. + + out->write( |ABAP Cheat Sheet Example: Working with XML and JSON in ABAP\n\n| ). + out->write( |1) Excursion: Converting string <-> xstring| ). + "In the following examples, many operations are performed using binary data. + "This excursion shows the conversion of string to xstring and the other way round + "using a codepage. The examples use UTF-8. + "For this purpose, you can, for example, use the cl_abap_conv_codepage class + "and the XCO library. + + "Storing XML data in a data object of type string + DATA(xml_string) = + `` && + ` ` && + ` LH` && + ` 400` && + ` ` && + ` Frankfurt` && + ` FRA` && + ` ` && + ` ` && + ` ` && + ` Berlin` && + ` SXF` && + ` ` && + ` ` && + ` ` && + ` ` && + ` DL` && + ` 1984` && + ` ` && + ` San Francisco` && + ` SFO` && + ` ` && + ` ` && + ` ` && + ` New York` && + ` JFK` && + ` ` && + ` ` && + ` ` && + ``. + + "string -> xstring + "Note: UTF-8 is used by default. Here, it is specified explicitly. + "Conversion errors are caught using the cx_sy_conversion_codepage class. + TRY. + DATA(conv_xstring) = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( xml_string ). + CATCH cx_sy_conversion_codepage. + ENDTRY. + + "xstring -> string + DATA(conv_string) = cl_abap_conv_codepage=>create_in( )->convert( conv_xstring ). + + "As an alternative, you can use methods of the XCO library. + "string -> xstring + DATA(conv_xstring_xco) = xco_cp=>string( xml_string + )->as_xstring( xco_cp_character=>code_page->utf_8 + )->value. + + "xstring -> string + DATA(conv_string_xco) = xco_cp=>xstring( conv_xstring_xco + )->as_string( xco_cp_character=>code_page->utf_8 + )->value. + + conv_string = format( conv_string ). + conv_string_xco = format( conv_string_xco ). + out->write( |\n| ). + out->write( `Results of the xstring to string conversions:` ). + out->write( |\n| ). + out->write( conv_string ). + out->write( |\n| ). + out->write( conv_string_xco ). + +********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `2) Processing XML Using Class Libraries` ) ). + out->write( |Excursion: Usable iXML/sXML Classes and Interfaces\n\n| ). + "Using a released CDS view, classes and interfaces are retrieved that + "have 'ixml' and 'sxml' in the name for you to explore the released classes + "and interfaces in this context. + + SELECT ReleasedObjectType, ReleasedObjectName, ReleaseState + FROM i_apisforclouddevelopment + WHERE releasestate = 'RELEASED' + AND + ( ReleasedObjectType = 'CLAS' OR ReleasedObjectType = 'INTF' ) + AND + ( ReleasedObjectName LIKE '%IXML%' OR ReleasedObjectName LIKE '%SXML%' ) + INTO TABLE @DATA(released_xml_libs). + + out->write( `No output. You can check the internal table content in the debugger to view the usable artifacts.` ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `3) Creating XML Data Using iXML` ) ). + "In the following example, XML data is created using the iXML library. + "This is done by creating DOM nodes step by step. The nodes are created as + "elements and attributes. Content is inserted into the XML data. + "The example uses an appropriate attribute setting so that the result + "represents XML data in asXML format. + "Note: You can check out more examples in the system by choosing CTRL + + "SHIFT + A in ADT and search for *demo_ixml*. + "For more information on the classes/methods used, check the documentation + "by choosing F2 in ADT when placing the cursor on a class/methods. + + "Creating one factory object of the access class cl_ixml_core using the + "create method. The object is used to access the iXML library. + DATA(ixml_cr) = cl_ixml_core=>create( ). + + "Creating a document + DATA(document_cr) = ixml_cr->create_document( ). + + "Step-by-step creation of DOM nodes + "Creating a root node + DATA(root) = document_cr->create_element_ns( name = 'abap' + prefix = 'asx' ). + root->set_attribute_ns( name = 'asx' + prefix = 'xmlns' + value = 'http://www.sap.com/abapxml' ). + root->set_attribute_ns( name = 'version' + value = '1.0' ). + document_cr->append_child( root ). + DATA(xml_node1) = document_cr->create_element_ns( prefix = 'asx' + name = 'values' ). + root->append_child( xml_node1 ). + DATA(xml_node2) = document_cr->create_element_ns( name = 'STRING' ). + xml_node1->append_child( xml_node2 ). + xml_node2->append_child( document_cr->create_text( 'Hello ABAP' ) ). + + "Creating a renderer (for rendering the XML document into the output stream) + DATA xml_doc TYPE xstring. + ixml_cr->create_renderer( document = document_cr + ostream = ixml_cr->create_stream_factory( )->create_ostream_xstring( string = xml_doc ) + )->render( ). + + "Getting XML data + DATA(xml_output) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_doc ) ). + out->write( xml_output ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `4) Parsing XML Data Using iXML` ) ). + "The example covers the following aspects: + "- Parsing XML data to a DOM object in one go + "- Directly reading nodes using various iXML methods + "- Directly reading nodes using element names + "- Reading using iterators, i.e. going over the XML nodes one after another + "- During the iteration, ... + " ... node properties are extracted using various iXML methods + " (and stored in an internal table for display purposes). + " ... the XML data is modified. + " ... a new element is created. + "- Rendering XML data + + "Internal table to store node properties for display purposes + DATA properties TYPE string_table. + + "Creating simple demo XML data to be used in the example + TRY. + DATA(some_xml) = cl_abap_conv_codepage=>create_out( )->convert( + `` && + ` hallo` && + ` how` && + ` are` && + `` ). + CATCH cx_sy_conversion_codepage. + ENDTRY. + + "Creating one factory object of the access class cl_ixml_core using the + "create method. It is used to access the iXML library. + DATA(ixml_pa) = cl_ixml_core=>create( ). + "Creaing an input stream that is used for the input of XML data + DATA(stream_factory_pa) = ixml_pa->create_stream_factory( ). + "Creating an XML document stored in DOM format in the memory + DATA(document_pa) = ixml_pa->create_document( ). + "Creating a parser + "It requires the following input parameters: input stream to be parsed, + "the XML document to which the stream is parsed, a factory required to create a stream + DATA(parser_pa) = ixml_pa->create_parser( + istream = stream_factory_pa->create_istream_xstring( string = some_xml ) + document = document_pa + stream_factory = stream_factory_pa ). + + "Parsing XML data to a DOM representation in one go. It is put in the memory. + "Note: You can also parse sequentially, and not in one go. + DATA(parsing_check) = parser_pa->parse( ). + IF parsing_check = 0. "Parsing was successful + + "Directly reading nodes using various iXML methods + + "Accessing the root element of the DOM. It can be used as the initial node + "for accessing subnodes. + "You can check the content of the variables in the debugger. + "Note: Multiple methods are available to further process the nodes. + DATA(root_element) = document_pa->get_root_element( ). + "First subnode + DATA(child_element) = root_element->get_first_child( ). + "Getting the value of that node + DATA(child_element_value) = child_element->get_value( ). + "Next adjacent node/getting the value + DATA(next_element_value) = child_element->get_next( )->get_value( ). + + "Directly reading nodes using element names + "The result is the first element searched for. + DATA(element_by_name) = document_pa->find_from_name( name = `word3` )->get_value( ). + "A lot more options are available such as access by attributes. + + "Reading using iterators, i.e. going over the XML nodes sequentially + + "Creating an iterator + DATA(iterator_pa) = document_pa->create_iterator( ). + DO. + "For the iteration, you can use the get_next method to process the nodes one after another. + "Note: Here, all nodes are respected. You can also create filters to go over specific nodes. + DATA(node_i) = iterator_pa->get_next( ). + IF node_i IS INITIAL. + EXIT. + ELSE. + "Extracting properties + "For display purposes, the properties are stored in an internal table. + APPEND |gid: { node_i->get_gid( ) } / type: { node_i->get_type( ) } / name: { node_i->get_name( ) } / value: { node_i->get_value( ) }| TO properties. + ENDIF. + + IF node_i->get_type( ) = if_ixml_node=>co_node_text. + "Modifying values + "Here, the values are capitalized. + node_i->set_value( to_upper( node_i->get_value( ) ) ). + ENDIF. + + "Creating a new element + IF node_i->get_value( ) = 'are'. + document_pa->create_simple_element_ns( name = 'word4' + value = 'you' + parent = node_i->get_parent( ) ). + ENDIF. + ENDDO. + + "Creating a renderer + DATA xml_pa TYPE xstring. + ixml_pa->create_renderer( document = document_pa + ostream = ixml_pa->create_stream_factory( )->create_ostream_xstring( string = xml_pa ) + )->render( ). + + "Getting XML + DATA(output_ixml_parsing) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_pa ) ). + + out->write( output_ixml_parsing ). + out->write( |\n| ). + out->write( `Node properties:` ). + out->write( properties ). + ELSE. + out->write( `Parsing was not successful.` ). + ENDIF. + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `5) Creating XML Data Using sXML (Token-Based Rendering)` ) ). + "For sXML, there are specialized writer classes, such as CL_SXML_STRING_WRITE. + "Writers created with this class render XML data to a byte string. + "The XML 1.0 format and UTF-8 are used by default in the create method. + "Here, the parameters are specified explicitly. + "Note: The interface IF_SXML_WRITER contains the components that are valid + "for all readers (the abstract superclass CL_SXML_WRITER includes this + "interface as well as implementations for all readers). In the example below, + "a cast is required so as to access special methods (such as open_element). + + DATA(writer) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 + encoding = 'UTF-8' ) ). + + TRY. + "Creating nodes (the order of the nodes is important) + writer->open_element( name = 'flights' ). + writer->open_element( name = 'flight' ). + writer->open_element( name = 'carrier' ). + writer->write_value( 'LH' ). + writer->close_element( ). + writer->open_element( name = 'flightnumber' ). + writer->write_value( '400' ). + writer->close_element( ). + writer->close_element( ). + writer->open_element( name = 'flight' ). + writer->open_element( name = 'carrier' ). + writer->write_value( 'DL' ). + writer->close_element( ). + writer->open_element( name = 'flightnumber' ). + writer->write_value( '1984' ). + writer->close_element( ). + writer->close_element( ). + writer->close_element( ). + CATCH cx_sxml_state_error INTO DATA(error_token). + out->write( error_token->get_text( ) ). + ENDTRY. + + "Getting XML data + "The XML data can be retrieved with the GET_OUTPUT method. + "Also here, a cast is required. The result is of type xstring. + DATA(xml_sxml) = CAST cl_sxml_string_writer( writer )->get_output( ). + + DATA(output_sxml_token_rendering) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_sxml ) ). + out->write( output_sxml_token_rendering ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `6) Creating XML Data using sXML (Object-Oriented Rendering)` ) ). + + DATA(writer_oo) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 + encoding = 'UTF-8' ) ). + + TRY. + writer_oo->write_node( writer_oo->new_open_element( name = 'flights' ) ). + + writer_oo->write_node( writer_oo->new_open_element( name = 'flight' ) ). + writer_oo->write_node( writer_oo->new_open_element( name = 'carrier' ) ). + DATA(val) = writer_oo->new_value( ). + val->set_value( 'AZ' ). + writer_oo->write_node( val ). + writer_oo->write_node( writer_oo->new_close_element( ) ). + writer_oo->write_node( writer_oo->new_open_element( name = 'flightnumber' ) ). + val = writer_oo->new_value( ). + val->set_value( '788' ). + writer_oo->write_node( val ). + writer_oo->write_node( writer_oo->new_close_element( ) ). + writer_oo->write_node( writer_oo->new_close_element( ) ). + + writer_oo->write_node( writer_oo->new_open_element( name = 'flight' ) ). + writer_oo->write_node( writer_oo->new_open_element( name = 'carrier' ) ). + val = writer_oo->new_value( ). + val->set_value( 'JL' ). + writer_oo->write_node( val ). + writer_oo->write_node( writer_oo->new_close_element( ) ). + writer_oo->write_node( writer_oo->new_open_element( name = 'flightnumber' ) ). + val = writer_oo->new_value( ). + val->set_value( '407' ). + writer_oo->write_node( val ). + writer_oo->write_node( writer_oo->new_close_element( ) ). + writer_oo->write_node( writer_oo->new_close_element( ) ). + + writer_oo->write_node( writer_oo->new_close_element( ) ). + CATCH cx_sxml_state_error INTO DATA(error_oo). + out->write( error_oo->get_text( ) ). + ENDTRY. + + DATA(xml_sxml_oo_rendering) = CAST cl_sxml_string_writer( writer_oo )->get_output( ). + + DATA(output_sxml_oo_rendering) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_sxml_oo_rendering ) ). + out->write( output_sxml_oo_rendering ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `7) Parsing XML Data using sXML (Token-Based Parsing)` ) ). + + "Creating demo XML data to be used in the example + TRY. + DATA(xml_to_parse) = cl_abap_conv_codepage=>create_out( )->convert( + `` && + `` && + ` ` && + ` A` && + ` 01-01-2024` && + ` ` && + ` ` && + ` abc` && + ` def` && + ` ghi` && + ` jkl` && + ` ` && + `` ). + CATCH cx_sy_conversion_codepage. + ENDTRY. + + "Creating an internal table for display purposes + DATA: BEGIN OF node_info, + node_type TYPE string, + prefix TYPE string, + name TYPE string, + nsuri TYPE string, + value_type TYPE string, + value TYPE string, + value_raw TYPE xstring, + END OF node_info, + nodes_tab LIKE TABLE OF node_info. + + "Creating reader + "Note: See the comments for the writer above which is similar. For readers, + "the interface IF_SXML_READER exists. In this example, no special methods + "are used. Therefore, a cast is not carried out. + DATA(reader) = cl_sxml_string_reader=>create( xml_to_parse ). + "DATA(reader_cast) = CAST if_sxml_reader( cl_sxml_string_reader=>create( xml_oo ) ). + + "To iterate accros all nodes, you can call the NEXT_NODE method. + TRY. + DO. + "Check out other available methods in ADT by placing the cursor behind -> + "and choosing CTRL + Space. + reader->next_node( ). + + "When reaching the end of the XML data, the loop is exited. + IF reader->node_type = if_sxml_node=>co_nt_final. + EXIT. + ENDIF. + + "You can access the properties of the node directly. + "For display purposes, the property information is stored in an internal table. + "The demo XML data that is used here does not include all properties. Therefore, + "the values for these are initial. + + "Node type, see the interface if_sxml_node + DATA(node_type) = SWITCH #( reader->node_type WHEN if_sxml_node=>co_nt_initial THEN `CO_NT_INITIAL` + WHEN if_sxml_node=>co_nt_element_open THEN `CO_NT_ELEMENT_OPEN` + WHEN if_sxml_node=>co_nt_element_close THEN `CO_NT_ELEMENT_CLOSE` + WHEN if_sxml_node=>co_nt_value THEN `CO_NT_VALUE` + WHEN if_sxml_node=>co_nt_attribute THEN `CO_NT_ATTRIBUTE` + ELSE `Error` ). + + DATA(prefix) = reader->prefix. "Namespace prefix + DATA(name) = reader->name. "Name of the element + DATA(nsuri) = reader->nsuri. "Namespace URI + + "Value type, see the interface if_sxml_value + DATA(value_type) = SWITCH #( reader->value_type WHEN 0 THEN `Initial` + WHEN if_sxml_value=>co_vt_none THEN `CO_VT_NONE` + WHEN if_sxml_value=>co_vt_text THEN `CO_VT_TEXT` + WHEN if_sxml_value=>co_vt_raw THEN `CO_VT_RAW` + WHEN if_sxml_value=>co_vt_any THEN `CO_VT_ANY` + ELSE `Error` ). + + DATA(value) = reader->value. "Character-like value (if it is textual data) + DATA(value_raw) = reader->value_raw. "Byte-like value (if it is raw data) + + APPEND VALUE #( node_type = node_type + prefix = prefix + name = name + nsuri = nsuri + value_type = value_type + value = value + value_raw = value_raw ) TO nodes_tab. + + "Once the method is called, you can directly access the attributes of the reader with the required + "properties of the node. When the parser is on the node of an element opening, you can use the method + "NEXT_ATTRIBUTE to iterate across the XML element attributes. + IF reader->node_type = if_sxml_node=>co_nt_element_open. + DO. + reader->next_attribute( ). + IF reader->node_type <> if_sxml_node=>co_nt_attribute. + EXIT. + ENDIF. + APPEND VALUE #( node_type = `attribute` + prefix = reader->prefix + name = reader->name + nsuri = reader->nsuri + value = reader->value + value_raw = reader->value_raw ) TO nodes_tab. + ENDDO. + ENDIF. + ENDDO. + CATCH cx_sxml_state_error INTO DATA(error_parse_token). + out->write( error_parse_token->get_text( ) ). + ENDTRY. + + out->write( `Node properties:` ). + out->write( nodes_tab ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `8) Parsing XML Data using sXML (Object-Oriented Parsing)` ) ). + + CLEAR nodes_tab. + DATA(reader_oo) = cl_sxml_string_reader=>create( xml_to_parse ). + + TRY. + DO. + "To iterate accros all nodes, you can call the READ_NEXT_NODE method. + "When the end of the XML data is reached, the returned value is initial. + DATA(node_oo) = reader_oo->read_next_node( ). + IF node_oo IS INITIAL. + EXIT. + ENDIF. + + "In object-oriented parsing, methods for token-based parsing are wrapped. + "An object-oriented access to the node is provided. + "References to objects that represent the current node are returned. + + "Getting the node type + DATA(n_type) = node_oo->type. + + "If the parser is currently on the node of an element opening, + "the node object has the class CL_SXML_OPEN_ELEMENT that implements the + "interface IF_SXML_OPEN_ELEMENT. With the methods included, you can + "access the XML attributes of the element, e.g. using the GET_ATTRIBUTES + "method to put the references for all attributes into an internal table. + "To access the attributes, a downcast is required. + + CASE n_type. + WHEN if_sxml_node=>co_nt_element_open. + DATA(open_element) = CAST if_sxml_open_element( node_oo ). + + APPEND VALUE #( node_type = `open element` + prefix = open_element->prefix + name = open_element->qname-name + nsuri = open_element->qname-namespace + ) TO nodes_tab. + + DATA(attributes) = open_element->get_attributes( ). + + LOOP AT attributes INTO DATA(attribute). + APPEND VALUE #( node_type = `attribute` + prefix = open_element->prefix + name = open_element->qname-name + nsuri = open_element->qname-namespace + value = SWITCH #( attribute->value_type WHEN if_sxml_value=>co_vt_text THEN attribute->get_value( ) ) + value_raw = SWITCH #( attribute->value_type WHEN if_sxml_value=>co_vt_raw THEN attribute->get_value_raw( ) ) + ) TO nodes_tab. + ENDLOOP. + + WHEN if_sxml_node=>co_nt_element_close. + DATA(close_element) = CAST if_sxml_close_element( node_oo ). + + APPEND VALUE #( node_type = `close element` + prefix = open_element->prefix + name = open_element->qname-name + nsuri = open_element->qname-namespace + ) TO nodes_tab. + + WHEN if_sxml_node=>co_nt_value. + DATA(value_node_oo) = CAST if_sxml_value_node( node_oo ). + + APPEND VALUE #( node_type = `value` + value = SWITCH #( value_node_oo->value_type WHEN if_sxml_value=>co_vt_text THEN value_node_oo->get_value( ) ) + value_raw = SWITCH #( value_node_oo->value_type WHEN if_sxml_value=>co_vt_raw THEN value_node_oo->get_value_raw( ) ) + ) TO nodes_tab. + + WHEN OTHERS. + APPEND VALUE #( node_type = `Error` ) TO nodes_tab. + ENDCASE. + ENDDO. + CATCH cx_sxml_state_error INTO DATA(error_parse_oo). + out->write( error_parse_oo->get_text( ) ). + ENDTRY. + + out->write( `Node properties:` ). + out->write( nodes_tab ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `XML Transformations` ) ). + + out->write( |9) Excursion: Available ABAP Cheat Sheet Transformations in the System\n\n| ). + "Excursion using the XCO library. In this example, tranformation programs are retrieved. + "A filter is applied. Because of a filter that is applied, only the ABAP cheat sheet + "transformation programs are returned. + + DATA(filter) = xco_cp_abap_repository=>object_name->get_filter( + xco_cp_abap_sql=>constraint->contains_pattern( 'ZDEMO_ABAP_%' ) ). + + DATA(filtered_transformations) = xco_cp_abap_repository=>objects->xslt->where( VALUE #( ( filter ) + ) )->in( xco_cp_abap=>repository )->get( ). + + IF filtered_transformations IS NOT INITIAL. + TYPES cst TYPE TABLE OF sxco_tf_object_name WITH EMPTY KEY. + DATA(cheat_sheet_transformations) = VALUE cst( FOR tr IN filtered_transformations ( tr->name ) ). + out->write( cheat_sheet_transformations ). + out->write( |\n| ). + out->write( `The code contains an implementation that gets all the transformations in the system.` ). + out->write( `You can check the content of the variable in the debugger. Among the transformations is the predefined identity transformation ID.` ). + ENDIF. + + "Getting all transformations in the system + "You can check the table content in the debugger. + DATA(all_transformations) = xco_cp_abap_repository=>objects->xslt->all->in( xco_cp_abap=>repository )->get( ). + IF all_transformations IS NOT INITIAL. + DATA(all_transformations_in_system) = VALUE cst( FOR tr IN all_transformations ( tr->name ) ). + ENDIF. + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `10) Transforming XML to XML Using XSLT` ) ). + "In this example, XML is transformed to XML. For this purpose, a simple XSLT + "program does the following: + "- All nodes and attributes are copied from the source XML to the target XML + " without any changes. + "- A match on two elements is performed. If matched, two new elements are created + " in the target XML. In this operation, calculations are carried out (free seats + " and the occupancy rate based on the values of maximum and occupied seats). + "Note: + "- The element names in the demo XML data are capitalized on purpose because the + " XML data is used in another example that uses the asXML format. In deserializations + " of XML data to ABAP data, the elements that are deserialized must be capitalized + " so that they can be identified. + "Tranformations are performed using CALL TRANSFORMATION statements. + + "Creating demo XML data to be used in the example + TRY. + DATA(xml_flights) = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( + `` && + ` ` && + ` AA` && + ` 17` && + ` 385` && + ` 369` && + ` ` && + ` ` && + ` LH` && + ` 400` && + ` 330` && + ` 319` && + ` ` && + `` ). + CATCH cx_sy_conversion_codepage. + ENDTRY. + + DATA xml_a TYPE xstring. + + CALL TRANSFORMATION zdemo_abap_xslt_fl + SOURCE XML xml_flights + RESULT XML xml_a. + + DATA(conv_xml_a) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_a ) ). + out->write( conv_xml_a ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `11) Transforming ABAP to XML Using XSLT` ) ). + "In the example, data entries are retrieved from a database table. Appropriate names for the + "table columns are used with the AS addition so that the transformation can be carried + "out based on the selected data. + "Note: The resulting XML has the asXML format. + + SELECT carrid AS carrier, + connid AS connectionid, + seatsmax AS maxSeats, + seatsocc AS occSeats + FROM zdemo_abap_fli + WHERE carrid = 'AZ' + INTO TABLE @DATA(fli_itab) + UP TO 2 ROWS. + + DATA xml_b TYPE xstring. + + CALL TRANSFORMATION zdemo_abap_xslt_fl + SOURCE flights = fli_itab + RESULT XML xml_b. + + DATA(conv_xml_b) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_b ) ). + out->write( conv_xml_b ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `12) ABAP <-> XML using Simple Transformations (1)` ) ). + "The following simple transformation examples transform ABAP to XML and back. The + "Simple Transformation is implemented in a way to transform to the HTML format. + "This example transforms string tables to html. + + DATA(string_table_a) = VALUE string_table( ( `abc` ) ( `def` ) ( `ghi` ) ). + + DATA xml_c TYPE xstring. + + "ABAP -> XML + CALL TRANSFORMATION zdemo_abap_st_strhtml + SOURCE string_table = string_table_a + RESULT XML xml_c. + + DATA(conv_xml_c) = format( cl_abap_conv_codepage=>create_in( )->convert( xml_c ) ). + out->write( `ABAP -> XML` ). + out->write( conv_xml_c ). + out->write( |\n| ). + + "XML -> ABAP + DATA string_table_b TYPE string_table. + CALL TRANSFORMATION zdemo_abap_st_strhtml + SOURCE XML xml_c + RESULT string_table = string_table_b. + + out->write( `XML -> ABAP` ). + out->write( string_table_b ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `13) ABAP <-> XML using Simple Transformations (2)` ) ). + "In this example, an internal table is transformed to XML using Simple Transformation. + "HTML tags are inserted into the XML data as literals. + + SELECT carrid, carrname, currcode, url + FROM zdemo_abap_carr + INTO TABLE @DATA(carr_tab_a) + UP TO 2 ROWS. + + "ABAP -> XML + DATA str_a TYPE string. + + "The following CALL TRANSFORMATION statement includes the OPTIONS + "addition. In this example, the XML header should not be added. + "So, you can take the resulting html and test it in an HTML viewer. + + CALL TRANSFORMATION zdemo_abap_st_carrhtml + SOURCE carrier_info = carr_tab_a + RESULT XML str_a + OPTIONS xml_header = 'NO'. + + out->write( `ABAP -> XML` ). + out->write( format( str_a ) ). + out->write( |\n| ). + + "XML -> ABAP + DATA carr_tab_b LIKE carr_tab_a. + + CALL TRANSFORMATION zdemo_abap_st_carrhtml + SOURCE XML str_a + RESULT carrier_info = carr_tab_b. + + out->write( `XML -> ABAP` ). + out->write( carr_tab_b ). + +*********************************************************************** + + out->write( zcl_demo_abap_aux=>heading( `ABAP <-> XML using XSLT (Using the Predefined Identity Transformation ID)` ) ). + "The following examples demonstrate serializations (ABAP to XML) and deserializations (XML to ABAP) + "using the predefined identity transformation ID. + "Note: In doing so, ABAP data is transformed to their asXML representations that can be used as an + " intermediate format and which define a mapping between ABAP data and XML. + + out->write( |14) Elementary type\n\n| ). + "The example uses type string as an elementary type. + + "ABAP -> XML + DATA xml_d TYPE xstring. + DATA(str_b) = `This is some string.`. + + CALL TRANSFORMATION id SOURCE txt = str_b + RESULT XML xml_d. + + DATA(conv_xml_d) = cl_abap_conv_codepage=>create_in( )->convert( xml_d ). + out->write( `ABAP -> XML` ). + out->write( format( conv_xml_d ) ). + out->write( |\n| ). + + "XML -> ABAP + DATA str_c TYPE string. + CALL TRANSFORMATION id SOURCE XML xml_d + RESULT txt = str_c. + + out->write( `XML -> ABAP` ). + out->write( str_c ). + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `15) Structures` ) ). + + SELECT SINGLE carrid, carrname, currcode, url + FROM zdemo_abap_carr + WHERE carrid = 'LH' + INTO @DATA(carr_struc_a). + + "ABAP -> XML + DATA xml_e TYPE xstring. + CALL TRANSFORMATION id SOURCE structure = carr_struc_a + RESULT XML xml_e. + + DATA(conv_xml_e) = cl_abap_conv_codepage=>create_in( )->convert( xml_e ). + out->write( `ABAP -> XML` ). + out->write( format( conv_xml_e ) ). + out->write( |\n| ). + + "XML -> ABAP + DATA carr_struc_b LIKE carr_struc_a. + CALL TRANSFORMATION id SOURCE XML xml_e + RESULT structure = carr_struc_b. + + out->write( `XML -> ABAP` ). + out->write( carr_struc_b ). + out->write( |\n| ). + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `16) Internal tables` ) ). + + SELECT carrid, connid, fldate, price, currency + FROM zdemo_abap_fli + WHERE carrid = 'JL' + INTO TABLE @DATA(fli_tab_a) + UP TO 2 ROWS. + + "ABAP -> XML + DATA xml_f TYPE xstring. + CALL TRANSFORMATION id SOURCE itab = fli_tab_a + RESULT XML xml_f. + + DATA(conv_xml_f) = cl_abap_conv_codepage=>create_in( )->convert( xml_f ). + out->write( `ABAP -> XML` ). + out->write( format( conv_xml_f ) ). + out->write( |\n| ). + + "XML -> ABAP + DATA fli_tab_b LIKE fli_tab_a. + CALL TRANSFORMATION id SOURCE XML xml_f + RESULT itab = fli_tab_b. + + out->write( `XML -> ABAP` ). + out->write( fli_tab_b ). + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `17) Data References` ) ). + + DATA(dref_a) = NEW i( 123 ). + + "ABAP -> XML + DATA xml_g TYPE xstring. + CALL TRANSFORMATION id SOURCE dref = dref_a + RESULT XML xml_g. + + DATA(conv_xml_g) = cl_abap_conv_codepage=>create_in( )->convert( xml_g ). + + out->write( `ABAP -> XML` ). + out->write( format( conv_xml_g ) ). + out->write( |\n| ). + + "XML -> ABAP + DATA dref_b LIKE dref_a. + CALL TRANSFORMATION id SOURCE XML xml_g + RESULT dref = dref_b. + + out->write( `XML -> ABAP` ). + out->write( dref_b->* ). + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `18) Object References` ) ). + "The following example demonstrates the serialization and deserialization of + "instances of classes (objects). For example, to serialize instance attributes, + "classes must implement the if_serializable_object interface. By default, all instance + "attributes of an object are serialized, regardless of their visibility section. + "However, you can change this behavior using the serialize_helper and deserialize_helper + "instance methods. As a result of the transformation, you get an asXML representation of + "the object. + "The example is implemented as follows: + "- The class implements the if_serializable_object interface. + "- There are 4 instance attributes of type string. + "- There are two instance methods: + " - One method concatenates two of the strings and assigns the resulting string to + " another string. + " - Another method concatenates two strings and converts the string to lowercase. + " The result is assigned to another string. + "- Serialization preserves instance attribute values in the asXML representation of the + " object. + "- During deserialization, the instance attribute values are transformed back and can + " be accessed. + "- The example includes the implementation of the serialize_helper and deserialize_helper + " instance methods. Without implementation, all instance attributes would be + " serialized/deserialized. The sample implementation limits serialization/deserialization. + " The fourth instance attribute, which is converted to a lowercase string when calling the + " method, is not part of the serialization/deserialization. See the implementation of the + " serialize_helper and deserialize_helper instance methods. They explicitly specify what + " to serialize and deserialize. + "- Note: For each output parameter of the serialize_helper method, you must specify an + " identically-named input parameter of the deserialize_helper method. The parameters must + " have the same type. + + DATA(oref_a) = NEW zcl_demo_abap_xml_json( ). + oref_a->attr_string_a = `AB`. + oref_a->attr_string_b = `AP`. + oref_a->concatenate_string( ). + oref_a->lowercase_string( ). + + out->write( `Value of instance attribute attr_lowercase_str for the created instance (before serialization/deserialization):` ). + out->write( oref_a->attr_lowercase_str ). + out->write( |\n| ). + + "ABAP -> XML + DATA xml_oref_a TYPE xstring. + CALL TRANSFORMATION id SOURCE oref = oref_a + RESULT XML xml_oref_a. + + DATA(conv_xml_oref_a) = cl_abap_conv_codepage=>create_in( )->convert( xml_oref_a ). + + out->write( `ABAP -> XML` ). + out->write( format( conv_xml_oref_a ) ). + out->write( |\n| ). + + "XML -> ABAP + DATA oref_b LIKE oref_a. + CALL TRANSFORMATION id SOURCE XML xml_oref_a + RESULT oref = oref_b. + + out->write( `XML -> ABAP` ). + out->write( oref_b->attr_string_a ). + out->write( oref_b->attr_string_b ). + out->write( oref_b->attr_concat_string ). + out->write( |\n| ). + IF oref_b->attr_lowercase_str IS INITIAL. + out->write( `The instance attribute attr_lowercase_str is initial. The serialization/deserialization is restricted.` ). + ENDIF. + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `19) CALL TRANSFORMATION Syntax: Specifying Transformations` ) ). + "As already covered in the examples above, transformations are specified after + "CALL TRANSFORMATION. They are either ... + + "... XSLT programs + CALL TRANSFORMATION zdemo_abap_st_carrhtml SOURCE carrier_info = carr_tab_a + RESULT XML str_a. + + "... predefined identity transformations + CALL TRANSFORMATION id SOURCE dref = dref_a + RESULT XML xml_g. + + "... dynamically specified transformation (valid for both XSLT and ST). In the examples above, + "the transformation is specified statically. Dynamic specifications are possible. A + "character-like data object in uppercase letters is expected in parentheses (either a named + "or unnamed data objects). + CALL TRANSFORMATION ('ID') SOURCE dref = dref_a + RESULT XML xml_g. + + "If a dynamically specified transformation is not found, an exception of the class + "CX_INVALID_TRANSFORMATION is raied. The example uses a named data object. + DATA(notr) = 'NON_EXISTENT_TRANSFORMATION'. + TRY. + CALL TRANSFORMATION (notr) SOURCE dref = dref_a + RESULT XML xml_g. + CATCH cx_invalid_transformation INTO DATA(error_non). + out->write( error_non->get_text( ) ). + ENDTRY. + + "... Simple Transformation + CALL TRANSFORMATION zdemo_abap_st_carrhtml SOURCE XML str_a + RESULT carrier_info = carr_tab_b. + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `20) CALL TRANSFORMATION Syntax: Sources of Transformations` ) ). + "The following examples use the predefined identity transformation ID. + "The result is asXML data and stored in a variable of type xstring. + "Multiple options and variants are possible. The examples cover a selection. + + out->write( `********** Source options for transforming XML data **********` ). + out->write( |\n| ). + + "Source: XML data in a data object of type string. It is implicitly transformed to + "XML in this case. + "Note: It must have character-like XML data in XML 1.0 format. + DATA(str_d) = `Hello world`. + DATA xml_h TYPE xstring. + CALL TRANSFORMATION id SOURCE XML str_d + RESULT XML xml_h. + + DATA(conv_xml_h) = cl_abap_conv_codepage=>create_in( )->convert( xml_h ). + + out->write( `Source: XML data in data object of type string` ). + out->write( format( conv_xml_h ) ). + out->write( |\n| ). + + "Source: XML data in a data object of type xstring + DATA(xml_i) = cl_abap_conv_codepage=>create_out( )->convert( `Hi ABAP` ). + DATA xml_j TYPE xstring. + CALL TRANSFORMATION id SOURCE XML xml_i + RESULT XML xml_j. + + DATA(conv_xml_j) = cl_abap_conv_codepage=>create_in( )->convert( xml_j ). + out->write( `Source: XML data in a data object of type xstring` ). + out->write( format( conv_xml_j ) ). + out->write( |\n| ). + + "Source: Standard table with character-like data type + DATA(stdtab_clike) = VALUE c50_tab_type( ( 'Hi' ) ( 'ABAP' ) ). + DATA xml_k TYPE xstring. + CALL TRANSFORMATION id SOURCE tab = stdtab_clike + RESULT XML xml_k. + + DATA(conv_xml_k) = cl_abap_conv_codepage=>create_in( )->convert( xml_k ). + out->write( `Source: Standard table with character-like data type` ). + out->write( format( conv_xml_k ) ). + out->write( |\n| ). + + "Source: Standard table with byte-like data type + DATA(stdtab_bytelike) = VALUE x30_tab_type( ( cl_abap_conv_codepage=>create_out( )->convert( `Hello` ) ) + ( cl_abap_conv_codepage=>create_out( )->convert( `ABAP` ) ) ). + DATA xml_l TYPE xstring. + CALL TRANSFORMATION id SOURCE xtab = stdtab_bytelike + RESULT XML xml_l. + + DATA(conv_xml_l) = cl_abap_conv_codepage=>create_in( )->convert( xml_l ). + out->write( `Source: Standard table with byte-like data type` ). + out->write( format( conv_xml_l ) ). + out->write( |\n| ). + + "Furthermore, some references to iXML and sXML libraries are possible. + "The following example covers sXML (an interface reference variable of type if_sxml_reader). + DATA(sxml_reader) = cl_sxml_string_reader=>create( xml_h ). + DATA xml_m TYPE xstring. + CALL TRANSFORMATION id SOURCE XML sxml_reader + RESULT XML xml_m. + + DATA(conv_xml_m) = cl_abap_conv_codepage=>create_in( )->convert( xml_m ). + out->write( `Source: Interface reference variable with TYPE REF TO if_sxml_reader` ). + out->write( format( conv_xml_m ) ). + out->write( |\n| ). + + out->write( `********** Source options for transforming ABAP data **********` ). + out->write( |\n| ). + "Using ... SOURCE ... without specifying XML + "One or multiple ABAP data objects can be specified. + + "Source: Data object of type string + "elem stands for the name of an XML element. + DATA(str_e) = `abcdef`. + DATA xml_n TYPE xstring. + CALL TRANSFORMATION id SOURCE elem = str_e + RESULT XML xml_n. + + DATA(conv_xml_n) = cl_abap_conv_codepage=>create_in( )->convert( xml_n ). + out->write( `Source: Character string in data object of type string` ). + out->write( format( conv_xml_n ) ). + out->write( |\n| ). + + "Source: Data object of type string + DATA(str_f) = `some string`. + DATA xml_o TYPE xstring. + CALL TRANSFORMATION id SOURCE txt = str_f + RESULT XML xml_o. + + DATA(conv_xml_o) = cl_abap_conv_codepage=>create_in( )->convert( xml_o ). + out->write( `Source: Character string of type string` ). + out->write( format( conv_xml_o ) ). + out->write( |\n| ). + + "Source: Multiple data objects + DATA a_i TYPE i VALUE 123. + DATA b_str TYPE string VALUE `Hallo`. + DATA c_p TYPE p LENGTH 5 DECIMALS 2 VALUE `4.56`. + DATA xml_p TYPE xstring. + + CALL TRANSFORMATION id SOURCE x = a_i + y = b_str + z = c_p + RESULT XML xml_p. + + DATA(conv_xml_p) = cl_abap_conv_codepage=>create_in( )->convert( xml_p ). + out->write( `Source: Multiple ABAP data objects in a static parameter list` ). + out->write( format( conv_xml_p ) ). + out->write( |\n| ). + + "Source: Dynamic specification of ABAP data objects in an internal table of + "type abap_trans_srcbind_tab + DATA(srctab) = VALUE abap_trans_srcbind_tab( + ( name = 'X' value = REF #( a_i ) ) + ( name = 'Y' value = REF #( b_str ) ) + ( name = 'Z' value = REF #( c_p ) ) ). + DATA xml_q TYPE xstring. + + CALL TRANSFORMATION id SOURCE (srctab) + RESULT XML xml_q. + + DATA(conv_xml_q) = cl_abap_conv_codepage=>create_in( )->convert( xml_q ). + out->write( `Source: Multiple ABAP data objects in an internal table` ). + out->write( format( conv_xml_q ) ). + +************************************************************************* + + out->write( zcl_demo_abap_aux=>heading( `21) CALL TRANSFORMATION Syntax: Results of Transformations` ) ). + "As in the examples above, the predefined identity transformation is used here. + + "Creating demo XML data to be used in the example as the source. + DATA(demo_xml) = cl_abap_conv_codepage=>create_out( )->convert( `Hi ABAP` ). + + out->write( `********** Result options for transforming to XML data ********** ` ). + out->write( |\n| ). + + "Result: Data object of type string + "The example uses the OPTIONS addition. The XML header should not be added. + DATA str_g TYPE string. + CALL TRANSFORMATION id SOURCE XML demo_xml + RESULT XML str_g + OPTIONS xml_header = 'NO'. + + out->write( `Result: Data object of type string` ). + out->write( str_g ). + out->write( |\n| ). + + "Data object of type xstring + DATA xml_r TYPE xstring. + CALL TRANSFORMATION id SOURCE XML demo_xml + RESULT XML xml_r. + + DATA(conv_xml_r) = cl_abap_conv_codepage=>create_in( )->convert( xml_r ). + out->write( `Result: Data object of type xstring` ). + out->write( format( conv_xml_r ) ). + out->write( |\n| ). + + "Data object declared inline (e.g. DATA(a) or FINAL(b)), which has then the type xstring + CALL TRANSFORMATION id SOURCE XML demo_xml + RESULT XML DATA(xml_s). + + DATA(conv_xml_s) = cl_abap_conv_codepage=>create_in( )->convert( xml_s ). + out->write( `Result: Data object declared inline (type xstring)` ). + out->write( format( conv_xml_s ) ). + out->write( |\n| ). + + "Standard table with character-like line type + DATA stdtab_clike_b TYPE c50_tab_type. + CALL TRANSFORMATION id SOURCE XML demo_xml + RESULT XML stdtab_clike_b + OPTIONS xml_header = 'NO'. + + out->write( `Result: Standard table with character-like line type` ). + out->write( stdtab_clike_b ). + out->write( |\n| ). + + "Standard table with byte-like line type + DATA stdtab_bytelike_b TYPE x30_tab_type. + CALL TRANSFORMATION id SOURCE XML demo_xml + RESULT XML stdtab_bytelike_b. + + out->write( `Result: Standard table with byte-like line type` ). + out->write( stdtab_bytelike_b ). + out->write( |\n| ). + + "Furthermore, some references to iXML and sXML libraries are possible. + "The following example covers sXML (an object reference variable of type ref to cl_sxml_string_writer) + "Other types are possible, for example JSON writers. + DATA(writer4tr) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 ). + CALL TRANSFORMATION id SOURCE XML demo_xml + RESULT XML writer4tr. + + DATA(xml_t) = writer4tr->get_output( ). + DATA(conv_xml_t) = cl_abap_conv_codepage=>create_in( )->convert( xml_t ). + out->write( `Result: Object reference variable with type ref to cl_sxml_string_writer` ). + out->write( format( conv_xml_t ) ). + out->write( |\n| ). + + out->write( `********** Result options for transforming to ABAP data **********` ). + out->write( |\n| ). + + "Similar to above, multiple ABAP data objects can be specified as a static parameter list. + "Here, the example from above is used. The tranformation is performed the other way round. + DATA d_i LIKE a_i. + DATA e_str LIKE b_str. + DATA f_p LIKE c_p. + + CALL TRANSFORMATION id SOURCE XML xml_p + RESULT x = d_i + y = e_str + z = f_p. + + out->write( `Result: Multiple ABAP data objects in a static parameter list` ). + out->write( d_i ). + out->write( e_str ). + out->write( f_p ). + out->write( |\n| ). + + "Specifying an internal table of type abap_trans_resbind_tab + DATA g_i LIKE a_i. + DATA h_str LIKE b_str. + DATA i_p LIKE c_p. + + "Note: Only bound parts are deserialized, i.e. the result table must be + "filled accordingly. + DATA(restab) = VALUE abap_trans_resbind_tab( + ( name = 'X' value = REF #( d_i ) ) + ( name = 'Y' value = REF #( e_str ) ) + ( name = 'Z' value = REF #( f_p ) ) ). + + CALL TRANSFORMATION id SOURCE XML xml_q + RESULT (restab). + + out->write( `Result: Multiple ABAP data objects in an internal table` ). + out->write( restab ). + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `22) Dealing with JSON Data` ) ). + "Note: When the identity transformation ID is used, the format is asJSON. + + "Elementary type + DATA str_h TYPE string VALUE `Hello`. + "ABAP -> JSON + "Creating a JSON writer + DATA(json_wr_a) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). + + CALL TRANSFORMATION id SOURCE hi = str_h + RESULT XML json_wr_a. + + DATA(json_a) = cl_abap_conv_codepage=>create_in( )->convert( json_wr_a->get_output( ) ). + + out->write( `ABAP -> JSON: Elementary type` ). + out->write( json_a ). + out->write( |\n| ). + + "JSON -> ABAP + DATA str_i TYPE string. + "Note: CALL TRANSFORMATION handles JSON sources implicitly. + CALL TRANSFORMATION id SOURCE XML json_a + RESULT hi = str_i. + + out->write( `JSON -> ABAP: Elementary type` ). + out->write( str_i ). + out->write( |\n| ). + + "Structure + SELECT SINGLE carrid, carrname, currcode, url + FROM zdemo_abap_carr + WHERE carrid = 'AZ' + INTO @DATA(carr_struc_c). + + "ABAP -> JSON + DATA(json_wr_b) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). + + CALL TRANSFORMATION id SOURCE structure = carr_struc_c + RESULT XML json_wr_b. + + DATA(json_b) = cl_abap_conv_codepage=>create_in( )->convert( json_wr_b->get_output( ) ). + out->write( `ABAP -> JSON: Structure` ). + out->write( json_b ). + out->write( |\n| ). + + "JSON -> ABAP + DATA carr_struc_d LIKE carr_struc_c. + CALL TRANSFORMATION id SOURCE XML json_b + RESULT structure = carr_struc_d. + + out->write( `JSON -> ABAP: Structure` ). + out->write( carr_struc_d ). + out->write( |\n| ). + + "Internal table + SELECT carrid, carrname, currcode, url + FROM zdemo_abap_carr + INTO TABLE @DATA(carr_tab_c) + UP TO 2 ROWS. + + "ABAP -> JSON + "This examples uses a cast to get access to further methods. + DATA(json_wr_c) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). + DATA(json_wr_cast) = CAST if_sxml_writer( json_wr_c ). + + "With the following method calls, the result is formatted. + json_wr_cast->set_option( option = if_sxml_writer=>co_opt_linebreaks ). + json_wr_cast->set_option( option = if_sxml_writer=>co_opt_indent ). + + CALL TRANSFORMATION id SOURCE itab = carr_tab_c + RESULT XML json_wr_c. + + DATA(json_c) = cl_abap_conv_codepage=>create_in( )->convert( json_wr_c->get_output( ) ). + out->write( `ABAP -> JSON: Internal table` ). + out->write( json_c ). + out->write( |\n| ). + + "JSON -> ABAP + DATA carr_tab_d LIKE carr_tab_c. + + CALL TRANSFORMATION id SOURCE XML json_c + RESULT itab = carr_tab_d. + + out->write( `JSON -> ABAP: Internal table` ). + out->write( carr_tab_d ). + out->write( |\n| ). + + "JSON -> XML + DATA(str_j) = + `{` && + `"flights": [` && + ` {` && + ` "carrier": "LH",` && + ` "connectionid": "400",` && + ` "from": "Frankfurt",` && + ` "to": "Berlin"` && + ` },` && + ` {` && + ` "carrier": "DL",` && + ` "connectionid": "400",` && + ` "from": "San Francisco",` && + ` "to": "New York"` && + ` }` && + `]` && + `}`. + + DATA(json_d) = cl_abap_conv_codepage=>create_out( )->convert( str_j ). + DATA(json_wr_d) = cl_sxml_string_reader=>create( json_d ). + DATA json2xml_ct TYPE xstring. + + "JSON -> XML using CALL TRANSFORMATION + CALL TRANSFORMATION id SOURCE XML json_wr_d + RESULT XML json2xml_ct. + + DATA(conv_json2xml_ct) = cl_abap_conv_codepage=>create_in( )->convert( json2xml_ct ). + + out->write( `JSON -> XML using CALL TRANSFORMATION` ). + out->write( format( conv_json2xml_ct ) ). + out->write( |\n| ). + + "JSON -> XML using sXML + DATA(reader_a) = cl_sxml_string_reader=>create( cl_abap_conv_codepage=>create_out( + )->convert( str_j ) ). + "XML writer (note the type specification in contrast to the previous examples) + DATA(xml_wr) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 ). + + TRY. + reader_a->next_node( ). + "The reader parses the data in one go by calling the SKIP_NODE method. + "The data is passed to an XML writer. + reader_a->skip_node( xml_wr ). + CATCH cx_sxml_parse_error INTO DATA(err_pa). + out->write( err_pa->get_text( ) ). + ENDTRY. + + DATA(json2xml_sxml) = cl_abap_conv_codepage=>create_in( )->convert( xml_wr->get_output( ) ). + out->write( `JSON -> XML using sXML` ). + out->write( format( json2xml_sxml ) ). + out->write( |\n| ). + + "XML -> JSON using CALL TRANSFORMATION + DATA(json_wr_f) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). + + CALL TRANSFORMATION id SOURCE XML json2xml_sxml + RESULT XML json_wr_f. + + DATA(xml2json_ct) = cl_abap_conv_codepage=>create_in( )->convert( json_wr_f->get_output( ) ). + out->write( `XML -> JSON using CALL TRANSFORMATION` ). + out->write( xml2json_ct ). + out->write( |\n| ). + + "XML -> JSON using sXML + DATA(reader_b) = cl_sxml_string_reader=>create( cl_abap_conv_codepage=>create_out( )->convert( xml2json_ct ) ). + DATA(json_wr) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ). + + TRY. + reader_b->next_node( ). + reader_b->skip_node( json_wr ). + CATCH cx_sxml_parse_error INTO DATA(err_xj). + out->write( err_xj->get_text( ) ). + ENDTRY. + + DATA(xml2json_sxml) = cl_abap_conv_codepage=>create_in( )->convert( json_wr->get_output( ) ). + out->write( `XML -> JSON using sXML` ). + out->write( xml2json_sxml ). + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `23) XCO Classes for JSON` ) ). + "Note: Unlike above, the following snippets do not work with asJSON as intermediate + "format. + + DATA: BEGIN OF carrier_struc, + carrier_id TYPE c length 3, + connection_id TYPE n length 4, + city_from TYPE c length 20, + city_to TYPE c length 20, + END OF carrier_struc. + + DATA carriers_tab like TABLE OF carrier_struc WITH EMPTY KEY. + + carrier_struc = VALUE #( carrier_id = 'AA' connection_id = '17' city_from = 'New York' city_to = 'San Francisco' ). + carriers_tab = VALUE #( ( carrier_id = 'AZ' connection_id = '788' city_from = 'Rome' city_to = 'Tokyo' ) + ( carrier_id = 'JL' connection_id = '408' city_from = 'Frankfurt' city_to = 'Tokyo' ) + ( carrier_id = 'LH' connection_id = '2402' city_from = 'Frankfurt' city_to = 'Berlin' ) ). + + "ABAP (structure) -> JSON using XCO + DATA(struc2json_xco) = xco_cp_json=>data->from_abap( carrier_struc )->to_string( ). + out->write( `ABAP (structure) -> JSON using XCO` ). + out->write( format( input = struc2json_xco xml = abap_false ) ). + out->write( |\n| ). + + "ABAP (internal table) -> JSON using XCO + DATA(itab2json_xco) = xco_cp_json=>data->from_abap( carriers_tab )->to_string( ). + out->write( `ABAP (internal table) -> JSON using XCO` ). + out->write( format( input = itab2json_xco xml = abap_false ) ). + out->write( |\n| ). + + "JSON -> ABAP (structure) using XCO + DATA json2struc_xco LIKE carrier_struc. + xco_cp_json=>data->from_string( struc2json_xco )->write_to( REF #( json2struc_xco ) ). + out->write( `JSON -> ABAP (structure) using XCO` ). + out->write( json2struc_xco ). + out->write( |\n| ). + + "JSON -> ABAP (internal table) using XCO + DATA json2itab_xco LIKE carriers_tab. + xco_cp_json=>data->from_string( itab2json_xco )->write_to( REF #( json2itab_xco ) ). + out->write( `JSON -> ABAP (internal table) using XCO` ). + out->write( json2itab_xco ). + out->write( |\n| ). + + "Creating JSON using XCO + "Check out more methods that offer more options to build the JSON by clicking + "CTRL + Space after '->' in ADT. + DATA(json_builder_xco) = xco_cp_json=>data->builder( ). + json_builder_xco->begin_object( + )->add_member( 'CarrierId' )->add_string( 'DL' + )->add_member( 'ConnectionId' )->add_string( '1984' + )->add_member( 'CityFrom' )->add_string( 'San Francisco' + )->add_member( 'CityTo' )->add_string( 'New York' + )->end_object( ). + + "Getting JSON data + DATA(json_created_xco) = json_builder_xco->get_data( )->to_string( ). + + out->write( `Creating JSON using XCO` ). + out->write( format( input = json_created_xco xml = abap_false ) ). + out->write( |\n| ). + + "Transforming the created JSON to ABAP (structure) + "Note: The JSON was intentionally created without the underscores in the + "name to demonstrate the 'apply' method. The following example demonstrates + "a transformation of camel case and underscore notation. As above, check out + "more options by clicking CTRL + Space after '...transformation->'. + CLEAR json2struc_xco. + xco_cp_json=>data->from_string( json_created_xco )->apply( VALUE #( + ( xco_cp_json=>transformation->pascal_case_to_underscore ) ) )->write_to( REF #( json2struc_xco ) ). + + out->write( `JSON -> ABAP (structure) using XCO demonstrating the apply method` ). + out->write( json2struc_xco ). + +************************************************************************ + + out->write( zcl_demo_abap_aux=>heading( `24) Excursion: Compressing and Decompressing Binary Data` ) ). + "You may want to process or store binary data. The data can be very large. + "You can compress the data in gzip format and decompress it for further processing using + "the cl_abap_gzip class. Check out appropriate exceptions to be caught. The simple example + "just specifies cx_root. See the class documentation for more information. + "This example uses a data object of type xstring from a previous example. + + "Compressing binary data + DATA xstr_comp TYPE xstring. + TRY. + cl_abap_gzip=>compress_binary( EXPORTING raw_in = xml_oref_a + IMPORTING gzip_out = xstr_comp ). + CATCH cx_root INTO DATA(error_comp). + out->write( error_comp->get_text( ) ). + ENDTRY. + + "Decompressing binary data + DATA xstr_decomp TYPE xstring. + TRY. + cl_abap_gzip=>decompress_binary( EXPORTING gzip_in = xstr_comp + IMPORTING raw_out = xstr_decomp ). + + CATCH cx_root INTO DATA(error_decomp). + out->write( error_decomp->get_text( ) ). + ENDTRY. + + "Checking the xstring length of the variables used and comparing the result + DATA(strlen_original_xstring) = xstrlen( xml_oref_a ). + out->write( |Length of original binary data object: { strlen_original_xstring }| ). + DATA(strlen_comp) = xstrlen( xstr_comp ). + out->write( |Length of compressed binary data object: { strlen_comp }| ). + DATA(strlen_decomp) = xstrlen( xstr_decomp ). + out->write( |Length of decompressed binary data object: { strlen_decomp }| ). + IF xml_oref_a = xstr_decomp. + out->write( `The decompressed binary data object has the same value as the original binary data object.` ). + ENDIF. + ENDMETHOD. + METHOD format. + TRY. + DATA(xstr) = cl_abap_conv_codepage=>create_out( )->convert( input ). + DATA(reader) = cl_sxml_string_reader=>create( xstr ). + DATA(writer) = CAST if_sxml_writer( cl_sxml_string_writer=>create( + type = COND #( WHEN xml = abap_true THEN if_sxml=>co_xt_xml10 ELSE if_sxml=>co_xt_json ) ) ). + writer->set_option( option = if_sxml_writer=>co_opt_linebreaks ). + writer->set_option( option = if_sxml_writer=>co_opt_indent ). + reader->next_node( ). + reader->skip_node( writer ). + string = cl_abap_conv_codepage=>create_in( )->convert( CAST cl_sxml_string_writer( writer )->get_output( ) ). + CATCH cx_root. + string = `Issue when formatting.`. + ENDTRY. + + ENDMETHOD. + + METHOD class_constructor. + "Filling demo database tables. + zcl_demo_abap_aux=>fill_dbtabs( ). + ENDMETHOD. + + METHOD concatenate_string. + attr_concat_string = attr_string_a && attr_string_b. + ENDMETHOD. + + METHOD deserialize_helper. + me->attr_string_a = attr_string_a. + me->attr_string_b = attr_string_b. + me->attr_concat_string = attr_concat_string. + ENDMETHOD. + + METHOD serialize_helper. + attr_string_a = me->attr_string_a. + attr_string_b = me->attr_string_b. + attr_concat_string = me->attr_concat_string. + ENDMETHOD. + + METHOD lowercase_string. + attr_lowercase_str = to_lower( attr_string_a && attr_string_b ). + ENDMETHOD. + ENDCLASS. \ No newline at end of file diff --git a/src/zdemo_abap_st_carriers_html.xslt.source.xml b/src/zdemo_abap_st_carrhtml.xslt.source.xml similarity index 92% rename from src/zdemo_abap_st_carriers_html.xslt.source.xml rename to src/zdemo_abap_st_carrhtml.xslt.source.xml index d5f590a..3a78a0b 100644 --- a/src/zdemo_abap_st_carriers_html.xslt.source.xml +++ b/src/zdemo_abap_st_carrhtml.xslt.source.xml @@ -1,49 +1,48 @@ - - - - - - - - -

Information about Carriers

-
- - - - - - - - - - - - - - -
- ID - - Name - - Currency - - Website -
- - - - - - - - - - -
- - - - - + + + + + + + +

Carrier Information

+ + + + + + + + + + + + + + + +
+ ID + + Name + + Currency + + Website +
+ + + + + + + + + + +
+ + + + + diff --git a/src/zdemo_abap_st_strtab_html.xslt.xml b/src/zdemo_abap_st_carrhtml.xslt.xml similarity index 86% rename from src/zdemo_abap_st_strtab_html.xslt.xml rename to src/zdemo_abap_st_carrhtml.xslt.xml index 46fc5d9..c8cac34 100644 --- a/src/zdemo_abap_st_strtab_html.xslt.xml +++ b/src/zdemo_abap_st_carrhtml.xslt.xml @@ -3,7 +3,7 @@ - ZDEMO_ABAP_ST_STRTAB_HTML + ZDEMO_ABAP_ST_CARRHTML E ST Demo diff --git a/src/zdemo_abap_st_strtab_html.xslt.source.xml b/src/zdemo_abap_st_strhtml.xslt.source.xml similarity index 88% rename from src/zdemo_abap_st_strtab_html.xslt.source.xml rename to src/zdemo_abap_st_strhtml.xslt.source.xml index c803894..b2f52ec 100644 --- a/src/zdemo_abap_st_strtab_html.xslt.source.xml +++ b/src/zdemo_abap_st_strhtml.xslt.source.xml @@ -1,23 +1,20 @@ - - - - - - - - -

Content of String Table

- - - - - - -
- -
- - -
- -
+ + + + + + +

String Table Content

+ + + + + + +
+ +
+ + +
+
diff --git a/src/zdemo_abap_st_carriers_html.xslt.xml b/src/zdemo_abap_st_strhtml.xslt.xml similarity index 86% rename from src/zdemo_abap_st_carriers_html.xslt.xml rename to src/zdemo_abap_st_strhtml.xslt.xml index 64a58a6..8b6c4b3 100644 --- a/src/zdemo_abap_st_carriers_html.xslt.xml +++ b/src/zdemo_abap_st_strhtml.xslt.xml @@ -3,7 +3,7 @@ - ZDEMO_ABAP_ST_CARRIERS_HTML + ZDEMO_ABAP_ST_STRHTML E ST Demo diff --git a/src/zdemo_abap_xslt_flights.xslt.source.xml b/src/zdemo_abap_xslt_fl.xslt.source.xml similarity index 97% rename from src/zdemo_abap_xslt_flights.xslt.source.xml rename to src/zdemo_abap_xslt_fl.xslt.source.xml index fdb1bb8..642a678 100644 --- a/src/zdemo_abap_xslt_flights.xslt.source.xml +++ b/src/zdemo_abap_xslt_fl.xslt.source.xml @@ -1,22 +1,20 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/zdemo_abap_xslt_flights.xslt.xml b/src/zdemo_abap_xslt_fl.xslt.xml similarity index 87% rename from src/zdemo_abap_xslt_flights.xslt.xml rename to src/zdemo_abap_xslt_fl.xslt.xml index 054fb8f..a712e2f 100644 --- a/src/zdemo_abap_xslt_flights.xslt.xml +++ b/src/zdemo_abap_xslt_fl.xslt.xml @@ -3,7 +3,7 @@ - ZDEMO_ABAP_XSLT_FLIGHTS + ZDEMO_ABAP_XSLT_FL E XSLT Demo