Registration

Dear SAP Community Member,
In order to fully benefit from what the SAP Community has to offer, please register at:
http://scn.sap.com
Thank you,
The SAP Community team.
Skip to end of metadata
Go to start of metadata

Author: Alexey Arseniev 
Submitted: 12.05.2017
Other code samples from me:

Why

Sometimes you need to access ABAP data objects dynamically. For example, when:

  • you do not know the structure of the ABAP object and to dynamically access value of the field forced to use ASSIGN .. COMPONENT with field symbol
  • you do a cross release development in ABAP and do not know if some field exists, so need dynamic access to data
  • you access data from optional ABAP component and also need dynamic access to ABAP structure field or internal table row
  • you need a key or index access to a dynamic internal table

Normally, if you need to access ABAP fields/structure component dynamically, you will end up in coding like this:

Accessing Data Objects Dynamically (as suggested in documentation)
FIELD-SYMBOLS: <table>  TYPE ANY TABLE,
               <line>   TYPE ANY,
               <field>  TYPE ANY.

ASSIGN COMPONENT `FIELD1` OF STRUCTURE <line> TO <field>.
IF <field> IS ASSIGNED.
  WRITE: <field>.
ENDIF.

That may be OK (however still not very convenient), but if you have a dynamic ABAP object with deeper structure, it becomes boring:

Accessing Deeply Nested Data Objects Dynamically
FIELD-SYMBOLS: 
  <table>  TYPE ANY TABLE,
  <line>   TYPE ANY,
  <field1>  TYPE ANY,
  <field2>  TYPE ANY,
  <field3>  TYPE ANY,
  <field4>  TYPE ANY.
 
ASSIGN COMPONENT `FIELD1` OF STRUCTURE <line> TO <field1>.
IF <field> IS ASSIGNED.
  ASSIGN COMPONENT `CHILD_1` OF STRUCTURE <fielld1> TO <field2>.
  IF <field2> IS ASSIGNED.
    ASSIGN COMPONENT `CHILD_11` OF STRUCTURE <fielld2> TO <field3>.
    IF <field3> IS ASSIGNED.
      ASSIGN COMPONENT `CHILD_111` OF STRUCTURE <fielld3> TO <field4>.
      IF <field4> IS ASSIGNED.
        WRITE: <field4>.
      ENDIF.
    ENDIF.
  ENDIF.
ENDIF.

And if one think about accessing dynamically elements from nested tables it would be at all - hell.

So, below one can find a helper class, which may help in such cases, in a lean and tasty way. (wink)

What it can

The accessor is a single class, with following features:

  • traversing of any data object (classes are not yet supported) passed as a reference to data or as a data.
  • traversing nested objects without any level limitations
  • automatically resolving reference variables (REF TO fields accessed same way as standard fields)
  • a method like or XPath-like ways of accessing data
  • read/modification access of elementary types
  • accessing table rows using index or key

Limitations

The code of dynamic data accessor class does not pretend to be complete and fully robust solution, but it may become like this if requests will come (wink)

Current limitations are following:

  • only ABAP data structures are supported. Traversing of ABAP objects/classes not yet supported, however possible
  • dynamic modification of tables (not data inside) is not supported. E.g you can not add/remove rows with API, but you can do it via reference to table
  • the syntax for key access of the rows in dynamic tables does not allow usage of the symbol "," as part of the query. No escaping is supported. 

Usage

Necessary declarations:

Type and data declarations for example below
TYPES:
 BEGIN OF t_properties,
   enabled     TYPE abap_bool,
   length      TYPE i,
   description TYPE c LENGTH 20,
 END OF t_properties,
 BEGIN OF t_data,
   id         TYPE i,
   properties TYPE t_properties,
   content    TYPE string,
 END OF t_data,
 BEGIN OF t_name_value,
   name  TYPE string,
   value TYPE string,
 END OF t_name_value,
 BEGIN OF t_example,
   flag   TYPE abap_bool,
   props  TYPE t_data,
   params TYPE SORTED TABLE OF t_name_value WITH UNIQUE KEY name,
 END OF t_example.
 
DATA: ls_data TYPE t_example,
      lr_data TYPE REF TO data,
      lr_ref  TYPE REF TO data,
      lv_int  TYPE i,
      lo_data TYPE REF TO zcl_dyn_access.

FIELD-SYMBOLS: <data> TYPE data.

ls_data-props-id      = 12345.
ls_data-props-content = `Some Content`.
ls_data-props-properties-enabled     = abap_false.
ls_data-props-properties-length      = 10.
ls_data-props-properties-description = `My description`.

GET REFERENCE OF ls_data INTO lr_data.

Simplest usage example:

Traversing ABAP data dynamically
CREATE OBJECT lo_data EXPORTING ir_data = lr_data.

" standard way (does not work on SAP_BASIS 700)
lr_ref = lo_data->at(`PROPS`)->at(`id`)->ref( ).
IF lr_ref IS BOUND.
  ASSIGN lr_ref->* TO <data>.
  WRITE: <data>.
ENDIF.
" XPath like
lr_ref = lo_data->at(`PROPS-ID`)->ref( ).
IF lr_ref IS BOUND.
  ASSIGN lr_ref->* TO <data>.
  WRITE: <data>.
ENDIF.

" using helper method for creation
lr_ref = zcl_dyn_access=>create( ir_data = lr_data iv_component = `PROPS-ID`)->ref( ).
IF lr_ref IS BOUND.
  ASSIGN lr_ref->* TO <data>.
  WRITE: <data>.
ENDIF.

" reading value directly
lo_data->at(`props-properties-length`)->value( IMPORTING ev_data = lv_int ).
WRITE: lv_int.

If you want to use modification operations, you can only operate with references when creating accessor object.

Dynamic data modification in ABAP in nice way
" modifing value
lr_ref = lo_data->at(`props-properties-length`)->ref( ).
ASSIGN lr_ref->* TO <data>.
<data> = 25.

" or even more simple
lo_data->at(`props-properties-length`)->set( 15 ).

The code is robust - accessing to not existing component of any level will not result in a crash but will return an empty reference or initial value.

Accessing not existing component
" reading not existing value returns initial value
lo_data->at(`props-properties-not_exist-length-not-exist`)->value( IMPORTING ev_data = lv_int ).
WRITE: lv_int. " -> 0

Working with tables:

Dynamic Access in ABAP in Easy way
DATA:
  ls_data  TYPE t_example,
  ls_line  LIKE LINE OF ls_data-params,
  lv_value TYPE string,
  lo_data  TYPE REF TO zcl_dyn_access.

ls_line-name = `KEY1`.
ls_line-value = `Value1`.
INSERT ls_line INTO TABLE ls_data-params.

ls_line-name = `KEY2`.
ls_line-value = `Value2`.
INSERT ls_line INTO TABLE ls_data-params.

zcl_dyn_access=>create( iv_data = ls_data iv_component = `params[2]-name`)->value( IMPORTING ev_data = lv_value ).
WRITE: lv_value.

zcl_dyn_access=>create( iv_data = ls_data iv_component = `params[name=KEY1]-value`)->value( IMPORTING ev_data = lv_value ).
WRITE: lv_value.

zcl_dyn_access=>create( iv_data = ls_data iv_component = `params`)->at(`[name=KEY1]-value`)->value( IMPORTING ev_data = lv_value ).
WRITE: lv_value.

zcl_dyn_access=>create( iv_data = ls_data iv_component = `params[name=KEY1, value=Value1]-value`)->value( IMPORTING ev_data = lv_value ).
WRITE: lv_value.

API

CREATE - Static Method Public Helper method for creating instance of dynamic accessor

  • > IR_DATA (ref to data)Importing Type Ref To DATA Reference to data (allows modification of embedded data)
  • > IV_DATA (data) - any data (modification of embedded data not allowed)
  • > IV_COMPONENT (string) - Sub-component name (XPath-like syntax is supported)
  • < RO_REF (ref to ZCL_DYN_ACCESS) - Reference to accessor object pointing to subcomponent

CONSTRUCTOR  - Instance Method Public Constructor

  • > IR_DATA (ref to data)Importing Type Ref To DATA Reference to data (allows modification of embedded data)
  • > IV_DATA (data) - any data (modification of embedded data not allowed)

AT - Instance Method Public Component accessor

  • > IV_COMPONENT (string) - Sub-component name (XPath-like syntax is supported)
  • < RO_REF (ref to ZCL_DYN_ACCESS) - Reference to accessor object pointing to subcomponent

EMPTY - Instance Method Public Returns TRUE if embedded object is initial (not bound)

  • < RV_VAL (boolean) - ABAP_TRUE if object is initial and data is not bound

REF - Instance Method Public Returns reference to embedded object

  • < RV_DATA (ref to data) - Reference to embedded data

VALUE - Instance Method Public Returns copy of the value

  • < EV_DATA (data) - Copy of the embedded data value, or initial if data is not bound

SET - Instance Method Public Sets value of the embedded object, if not initial

  • > IV_DATA (data)  - New value for embedded object
  • < RV_SUCCESS (boolean) - ABAP_TRUE, if data was successfully modified

XPath-like dynamic data access

To access nested components you can use a nice, object-oriented way, using nested calls of AT method (it is robust, and would not crash accessing not existing components), as

lo_object->at('subcomp1')->at('subcomp11')->...

But if you prefer more compact form, or run code on SAP_BASIS < 702 (nested method calls are not supported), you may use XPath-like syntax for accessing components. Like this:

lo_object->at('subcomp1-subcomp11-subcomp111')

or like this

lo_object->at('subcomp1->subcomp11->subcomp111')

The syntax:

  • You can use any symbol (or combinations of symbols) as a component separator, except "[", "]", "=", ",". Recommended separator symbol is "-".
  • For dynamic index access of rows in nested tables use "[index]" after the component name. E.g. "table_name[2]". The indexing starts from 1. If the accessor object references table data object directly, you may skip component name. E.g. "[2]". You may continue accessing components after index access, e.g. : "table_a[1]-struct-table_b[2]". If you do out of range access, you got an empty reference back. Index access works only with index tables (STANDARD, SORTED). 
  • For dynamic key access of rows in nested tables use "(key=value)" for single key lookup, "(key1=value1, key2=value2)" for multi-key lookup, "(value)" for table line lookup. You can NOT search for values containing ",". You can use nested lookups: "table_a(key1=value1)-table_b(key2=value2, key3=value3)". Values used in a query shall be assignable to field structures. 

The Code

The actual code for the helper:

ZCL_DYN_ACCESS - Dynamic Data Access For ABAP source code
*----------------------------------------------------------------------*
*       CLASS ZCL_DYN_ACCESS DEFINITION
*----------------------------------------------------------------------*
* Documentation can be found on SCN: 
" https://wiki.scn.sap.com/wiki/display/Snippets/Dynamic+Data+Accessor+Helper+Class+for+ABAP
*----------------------------------------------------------------------*
CLASS zcl_dyn_access DEFINITION.

  PUBLIC SECTION.

    CLASS-METHODS create
      IMPORTING
        ir_data       TYPE REF TO data OPTIONAL
        iv_data       TYPE data OPTIONAL
        iv_component  TYPE string OPTIONAL
      RETURNING
        VALUE(ro_ref) TYPE REF TO zcl_dyn_access .
    METHODS constructor
      IMPORTING
        ir_data TYPE REF TO data OPTIONAL
        iv_data TYPE data OPTIONAL .
    METHODS at
      IMPORTING
        iv_component  TYPE string OPTIONAL
      RETURNING
        VALUE(ro_ref) TYPE REF TO zcl_dyn_access .
    METHODS empty
      RETURNING
        VALUE(rv_val) TYPE abap_bool .
    METHODS ref
      RETURNING
        VALUE(rv_data) TYPE REF TO data .
    METHODS value
      EXPORTING
        ev_data TYPE data .
    METHODS set
      IMPORTING
        iv_data           TYPE data
      RETURNING
        VALUE(rv_success) TYPE abap_bool .
  PROTECTED SECTION.

    DATA mr_data TYPE REF TO data .

    CLASS-METHODS deref
      IMPORTING
        ir_data        TYPE REF TO data
      RETURNING
        VALUE(rr_data) TYPE REF TO data .
    METHODS at_int
      IMPORTING
        iv_component  TYPE string OPTIONAL
        iv_index      TYPE i OPTIONAL
        iv_keys       TYPE string OPTIONAL
      RETURNING
        VALUE(ro_ref) TYPE REF TO zcl_dyn_access .
ENDCLASS.

CLASS zcl_dyn_access IMPLEMENTATION.

  METHOD at.
    DATA:
      lv_component TYPE string,
      lv_sindex    TYPE string,
      lv_keys      TYPE string,
      lv_index     TYPE i,
      lt_hier      TYPE match_result_tab.

    FIELD-SYMBOLS:
      <component> LIKE LINE OF lt_hier,
      <sub_match> TYPE LINE OF submatch_result_tab.

    FIND ALL OCCURRENCES OF REGEX `(\w+)?(?:\[(?:(\d+)|([^\]]+))\])?` IN iv_component RESULTS lt_hier.

    ro_ref = me.

    LOOP AT lt_hier ASSIGNING <component> WHERE length IS NOT INITIAL.
      CHECK ro_ref->empty( ) EQ abap_false.
      READ TABLE <component>-submatches INDEX 1 ASSIGNING <sub_match>.
      IF <sub_match>-length IS INITIAL.
        CLEAR lv_component.
      ELSE.
        lv_component = iv_component+<sub_match>-offset(<sub_match>-length).
        TRANSLATE lv_component TO UPPER CASE.
      ENDIF.
      READ TABLE <component>-submatches INDEX 2 ASSIGNING <sub_match>.
      IF <sub_match>-length IS INITIAL.
        CLEAR lv_index.
      ELSE.
        lv_index = lv_sindex = iv_component+<sub_match>-offset(<sub_match>-length).
      ENDIF.
      READ TABLE <component>-submatches INDEX 3 ASSIGNING <sub_match>.
      IF <sub_match>-length IS INITIAL.
        CLEAR lv_keys.
      ELSE.
        lv_keys = iv_component+<sub_match>-offset(<sub_match>-length).
      ENDIF.
      ro_ref = ro_ref->at_int( iv_component = lv_component iv_index = lv_index iv_keys = lv_keys ).
    ENDLOOP.
  ENDMETHOD.                    "at_int

  METHOD at_int.

    DATA: lv_key   TYPE string,
          lv_value TYPE string,
          lt_keys  TYPE match_result_tab,
          lr_data  TYPE REF TO data,
          lo_type  TYPE REF TO cl_abap_typedescr.

    FIELD-SYMBOLS: <data>      TYPE data,
                   <comp>      TYPE data,
                   <key>       LIKE LINE OF lt_keys,
                   <sub_match> TYPE LINE OF submatch_result_tab,
                   <ref>       TYPE REF TO data,
                   <table>     TYPE ANY TABLE,
                   <idx_table> TYPE INDEX TABLE.

    IF mr_data IS BOUND.
      IF iv_component IS NOT INITIAL.
        ASSIGN mr_data->* TO <data>.
        ASSIGN COMPONENT iv_component OF STRUCTURE <data> TO <comp>.
        IF <comp> IS ASSIGNED.
          GET REFERENCE OF <comp> INTO lr_data.
          lr_data = deref( lr_data ).
          ASSIGN lr_data TO <ref>.
        ENDIF.
      ELSE.
        ASSIGN mr_data TO <ref>.
      ENDIF.
    ENDIF.

    IF <ref> IS ASSIGNED AND ( iv_index IS NOT INITIAL OR iv_keys IS NOT INITIAL ).
      lo_type = cl_abap_typedescr=>describe_by_data_ref( <ref> ).
      IF lo_type->kind EQ cl_abap_typedescr=>kind_table.
        " check for table index access
        IF iv_index IS NOT INITIAL.
          ASSIGN <ref>->* TO <idx_table>.
          IF sy-subrc IS INITIAL.
            READ TABLE <idx_table> INDEX iv_index REFERENCE INTO <ref>.
            IF sy-subrc IS NOT INITIAL.
              UNASSIGN <ref>.
            ENDIF.
          ELSE.
            UNASSIGN <ref>.
          ENDIF.
        ELSEIF iv_keys IS NOT INITIAL.
          ASSIGN <ref>->* TO <table>.
          IF sy-subrc IS INITIAL.
            CREATE DATA lr_data LIKE LINE OF <table>.
            ASSIGN lr_data->* TO <data>.
            FIND ALL OCCURRENCES OF REGEX `(\w+)\s*=\s*([^,]*),?` IN iv_keys RESULTS lt_keys.
            IF sy-subrc IS INITIAL.
              LOOP AT lt_keys ASSIGNING <key>.
                READ TABLE <key>-submatches INDEX 1 ASSIGNING <sub_match>.
                lv_key = iv_keys+<sub_match>-offset(<sub_match>-length).
                TRANSLATE lv_key TO UPPER CASE.
                READ TABLE <key>-submatches INDEX 2 ASSIGNING <sub_match>.
                lv_value = iv_keys+<sub_match>-offset(<sub_match>-length).
                ASSIGN COMPONENT lv_key OF STRUCTURE <data> TO <comp>.
                CHECK sy-subrc IS INITIAL.
                <comp> = lv_value.
              ENDLOOP.
            ELSE.
              <data> = lv_key.
            ENDIF.
            READ TABLE <table> FROM <data> REFERENCE INTO <ref>.
            IF sy-subrc IS NOT INITIAL.
              UNASSIGN <ref>.
            ENDIF.
          ELSE.
            UNASSIGN <ref>.
          ENDIF.
        ENDIF.
      ENDIF.
    ENDIF.

    IF <ref> IS ASSIGNED.
      CREATE OBJECT ro_ref
        EXPORTING
          ir_data = <ref>.
    ELSE.
      CREATE OBJECT ro_ref.
    ENDIF.
  ENDMETHOD.                    "at_int

  METHOD constructor.
    IF ir_data IS NOT INITIAL.
      mr_data = ir_data.
    ELSEIF iv_data IS SUPPLIED.
      GET REFERENCE OF iv_data INTO mr_data.
    ENDIF.
    mr_data = deref( mr_data ).
  ENDMETHOD.                    "constructor

  METHOD create.
    IF iv_data IS SUPPLIED.
      CREATE OBJECT ro_ref
        EXPORTING
          iv_data = iv_data.
    ELSE.
      CREATE OBJECT ro_ref
        EXPORTING
          ir_data = ir_data.
    ENDIF.

    IF iv_component IS NOT INITIAL.
      ro_ref = ro_ref->at( iv_component ).
    ENDIF.
  ENDMETHOD.                    "create

  METHOD deref.

    DATA: lo_type TYPE REF TO cl_abap_typedescr.

    FIELD-SYMBOLS: <data> TYPE data.

    rr_data = ir_data.
    IF rr_data IS NOT INITIAL.
      lo_type = cl_abap_typedescr=>describe_by_data_ref( ir_data ).
      IF lo_type->kind EQ cl_abap_typedescr=>kind_ref.
        ASSIGN ir_data->* TO <data>.
        rr_data = deref( <data> ).
      ENDIF.
    ENDIF.

  ENDMETHOD.                    "deref

  METHOD empty.
    IF mr_data IS INITIAL.
      rv_val = abap_true.
    ENDIF.
  ENDMETHOD.                    "empty

  METHOD ref.
    rv_data = mr_data.
  ENDMETHOD.                    "ref

  METHOD set.

    FIELD-SYMBOLS: <data> TYPE data.

    IF mr_data IS BOUND.
      ASSIGN mr_data->* TO <data>.
      <data> = iv_data.
      rv_success = abap_true.
    ENDIF.

  ENDMETHOD.

  METHOD value.

    DATA: lo_type_out TYPE REF TO cl_abap_typedescr,
          lo_type_in  TYPE REF TO cl_abap_typedescr.

    FIELD-SYMBOLS: <data> TYPE data.

    CLEAR ev_data.

    IF mr_data IS BOUND.
      ASSIGN mr_data->* TO <data>.
      lo_type_out = cl_abap_typedescr=>describe_by_data( ev_data ).
      lo_type_in = cl_abap_typedescr=>describe_by_data( <data> ).
      IF lo_type_out->kind EQ lo_type_in->kind.
        ev_data = <data>.
      ENDIF.
    ENDIF.

  ENDMETHOD.                    "value
  
ENDCLASS.

And unit tests, if you would like to do your own modifications and want tp validate that it still works:

Unit tests for ZCL_DYN_ACCESS
CLASS lc_ut DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.

  PUBLIC SECTION.
    TYPES:
      BEGIN OF t_properties,
        enabled     TYPE abap_bool,
        length      TYPE i,
        description TYPE c LENGTH 20,
      END OF t_properties,
      BEGIN OF t_data,
        id         TYPE i,
        properties TYPE t_properties,
        content    TYPE string,
      END OF t_data,
      BEGIN OF t_name_value,
        name  TYPE string,
        value TYPE string,
      END OF t_name_value,
      BEGIN OF t_example,
        flag   TYPE abap_bool,
        props  TYPE t_data,
        params TYPE SORTED TABLE OF t_name_value WITH UNIQUE KEY name,
      END OF t_example.

    METHODS: test_basic_actions FOR TESTING.
    METHODS: test_table_access FOR TESTING.

ENDCLASS.       "lc_ut


CLASS lc_ut IMPLEMENTATION.

  METHOD test_basic_actions.

    DATA: ls_data TYPE t_example,
          lr_data TYPE REF TO data,
          lr_ref  TYPE REF TO data,
          lv_int  TYPE i,
          lo_data TYPE REF TO zcl_dyn_access.

    FIELD-SYMBOLS: <data> TYPE data.

    ls_data-props-id      = 12345.
    ls_data-props-content = `Some Content`.
    ls_data-props-properties-enabled     = abap_false.
    ls_data-props-properties-length      = 10.
    ls_data-props-properties-description = `My description`.

    GET REFERENCE OF ls_data INTO lr_data.

    CREATE OBJECT lo_data EXPORTING ir_data = lr_data.

    " standard way (does not work on SAP_BASIS 700)
    lr_ref = lo_data->at(`PROPS`)->at(`id`)->ref( ).
    cl_aunit_assert=>assert_bound( act = lr_ref msg = `Dynamic access to existing property fails!` ).

    ASSIGN lr_ref->* TO <data>.
    cl_aunit_assert=>assert_equals( act = <data> exp = ls_data-props-id msg = `Dynamic access to existing property fails!` ).

    lr_ref = lo_data->at(`PROPS`)->at(`key`)->ref( ).
    cl_aunit_assert=>assert_not_bound( act = lr_ref msg = `Dynamic access to NOT existing property fails!` ).

    " XPath like
    lr_ref = lo_data->at(`PROPS-ID`)->ref( ).
    cl_aunit_assert=>assert_bound( act = lr_ref msg = `Dynamic access to existing property fails!` ).

    ASSIGN lr_ref->* TO <data>.
    cl_aunit_assert=>assert_equals( act = <data> exp = ls_data-props-id msg = `Dynamic access to existing property fails!` ).

    " using helper method for creation
    lr_ref = zcl_dyn_access=>create( ir_data = lr_data iv_component = `PROPS-ID`)->ref( ).
    cl_aunit_assert=>assert_bound( act = lr_ref msg = `Dynamic access to existing property fails!` ).

    ASSIGN lr_ref->* TO <data>.
    cl_aunit_assert=>assert_equals( act = <data> exp = ls_data-props-id msg = `Dynamic access to existing property fails!` ).

    " reading value
    lo_data->at(`props-properties-length`)->value( IMPORTING ev_data = lv_int ).
    cl_aunit_assert=>assert_equals( act = lv_int exp = ls_data-props-properties-length msg = `Dynamic read of existing the property fails!` ).

    lv_int = 25.
    lo_data->at(`props-properties-len`)->value( IMPORTING ev_data = lv_int ).
    cl_aunit_assert=>assert_initial( act = lv_int msg = `Dynamic read of the NOT existing property fails!` ).

    " modifing value
    lv_int = 25.
    lr_ref = lo_data->at(`props-properties-length`)->ref( ).
    ASSIGN lr_ref->* TO <data>.
    <data> = lv_int.
    cl_aunit_assert=>assert_equals( act = lv_int exp = ls_data-props-properties-length msg = `Dynamic modification of the existing property fails!` ).

    lv_int = 15.
    lo_data->at(`props-properties-length`)->set( lv_int ).
    cl_aunit_assert=>assert_equals( act = lv_int exp = ls_data-props-properties-length msg = `Dynamic modification of the existing property fails!` ).

    " degenerated example
    lv_int = 15.
    lo_data = zcl_dyn_access=>create( iv_data = lv_int ).
    ASSIGN lr_ref->* TO <data>.
    cl_aunit_assert=>assert_equals( act = <data> exp = lv_int msg = `Dynamic access of existing the property fails!` ).

  ENDMETHOD.

  METHOD test_table_access.

    DATA:
      ls_data  TYPE t_example,
      ls_line  LIKE LINE OF ls_data-params,
      lv_value TYPE string,
      lo_data  TYPE REF TO zcl_dyn_access.

    ls_line-name = `KEY1`.
    ls_line-value = `Value1`.
    INSERT ls_line INTO TABLE ls_data-params.

    ls_line-name = `KEY2`.
    ls_line-value = `Value2`.
    INSERT ls_line INTO TABLE ls_data-params.

    lo_data = zcl_dyn_access=>create( iv_data = ls_data iv_component = `params[2]-name`).
    lo_data->value( IMPORTING ev_data = lv_value ).

    cl_aunit_assert=>assert_equals( act = lv_value exp = `KEY2` msg = `Dynamic read to table item by index fails!` ).

    lo_data = zcl_dyn_access=>create( iv_data = ls_data iv_component = `params[name=KEY1]-value`).
    lo_data->value( IMPORTING ev_data = lv_value ).

    cl_aunit_assert=>assert_equals( act = lv_value exp = `Value1` msg = `Dynamic read to table item by key index fails!` ).

    lo_data = zcl_dyn_access=>create( iv_data = ls_data iv_component = `params`)->at(`[name=KEY1]-value`).
    lo_data->value( IMPORTING ev_data = lv_value ).

    cl_aunit_assert=>assert_equals( act = lv_value exp = `Value1` msg = `Dynamic read to table item by key index fails!` ).

    lo_data = zcl_dyn_access=>create( iv_data = ls_data iv_component = `params[name=KEY1, value=Value1]-value`).
    lo_data->value( IMPORTING ev_data = lv_value ).

    cl_aunit_assert=>assert_equals( act = lv_value exp = `Value1` msg = `Dynamic read to table item by key index fails!` ).

  ENDMETHOD.

ENDCLASS.