Text tables can be utilized to export SAP internal tables into text files properly or to share them with a consistent format on communication platforms.

Function


FUNCTION ZABAP2TEXTTABLE.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(IT_DATA) TYPE  ANY TABLE
*"  EXPORTING
*"     REFERENCE(EV_TEXT_TABLE) TYPE  STRING
*"  EXCEPTIONS
*"      CONVERSION_ERROR
*"----------------------------------------------------------------------

  TYPES: BEGIN OF ty_col_info,
           name         TYPE abap_compname,
           display_name TYPE string,
           max_width    TYPE i,
           is_numeric   TYPE abap_bool,
         END OF ty_col_info.

  DATA: lo_tabledescr  TYPE REF TO cl_abap_tabledescr,
        lo_structdescr TYPE REF TO cl_abap_structdescr,
        lo_typedescr   TYPE REF TO cl_abap_typedescr,
        lt_components  TYPE abap_component_tab,
        ls_component   TYPE abap_componentdescr,
        lt_col_info    TYPE TABLE OF ty_col_info,
        ls_col_info    TYPE ty_col_info,
        lv_field_value TYPE string,
        lv_line        TYPE string,
        lv_border      TYPE string,
        lv_separator   TYPE string,
        lv_cell        TYPE string,
        lv_dashes      TYPE string,
        lv_width       TYPE i,
        lv_val_len     TYPE i,
        lv_col_count   TYPE i,
        lv_col_index   TYPE i,
        lv_newline     TYPE string.

  FIELD-SYMBOLS:    TYPE any,
                  TYPE any.

  CLEAR ev_text_table.
  lv_newline = cl_abap_char_utilities=>newline.

* ----------------------------------------------------------------------
* 1. Retrieve table structure using RTTI
* ----------------------------------------------------------------------
  TRY.
      lo_typedescr = cl_abap_tabledescr=>describe_by_data( it_data ).
      lo_tabledescr ?= lo_typedescr.
      lo_structdescr ?= lo_tabledescr->get_table_line_type( ).
      lt_components = lo_structdescr->get_components( ).
    CATCH cx_sy_move_cast_error.
      RAISE conversion_error.
  ENDTRY.

  IF lt_components IS INITIAL.
    RAISE conversion_error.
  ENDIF.

* ----------------------------------------------------------------------
* 2. Collect column metadata and initialize widths
* ----------------------------------------------------------------------
  LOOP AT lt_components INTO ls_component.
    " Skip deep types (tables, structures, references)
    IF ls_component-type->kind = cl_abap_typedescr=>kind_table OR
       ls_component-type->kind = cl_abap_typedescr=>kind_struct OR
       ls_component-type->kind = cl_abap_typedescr=>kind_ref.
      CONTINUE.
    ENDIF.

    CLEAR ls_col_info.
    ls_col_info-name = ls_component-name.
    ls_col_info-display_name = to_lower( ls_component-name ).
    ls_col_info-max_width = strlen( ls_col_info-display_name ).

    " Flag numeric types for right-alignment
    IF ls_component-type->type_kind = cl_abap_typedescr=>typekind_int OR
       ls_component-type->type_kind = cl_abap_typedescr=>typekind_int1 OR
       ls_component-type->type_kind = cl_abap_typedescr=>typekind_int2 OR
       ls_component-type->type_kind = cl_abap_typedescr=>typekind_packed OR
       ls_component-type->type_kind = cl_abap_typedescr=>typekind_float OR
       ls_component-type->type_kind = cl_abap_typedescr=>typekind_decfloat OR
       ls_component-type->type_kind = cl_abap_typedescr=>typekind_decfloat16 OR
       ls_component-type->type_kind = cl_abap_typedescr=>typekind_decfloat34.
      ls_col_info-is_numeric = abap_true.
    ENDIF.

    APPEND ls_col_info TO lt_col_info.
  ENDLOOP.

  lv_col_count = lines( lt_col_info ).
  IF lv_col_count = 0.
    RAISE conversion_error.
  ENDIF.

* ----------------------------------------------------------------------
* 3. Scan data rows to determine maximum column widths
* ----------------------------------------------------------------------
  LOOP AT it_data ASSIGNING .
    LOOP AT lt_col_info INTO ls_col_info.
      lv_col_index = sy-tabix.
      ASSIGN COMPONENT ls_col_info-name OF STRUCTURE  TO .
      IF sy-subrc = 0.
        TRY.
            lv_field_value = .
          CATCH cx_root.
            CLEAR lv_field_value.
        ENDTRY.
        CONDENSE lv_field_value.
        lv_val_len = strlen( lv_field_value ).
        IF lv_val_len > ls_col_info-max_width.
          ls_col_info-max_width = lv_val_len.
          MODIFY lt_col_info FROM ls_col_info INDEX lv_col_index.
        ENDIF.
      ENDIF.
    ENDLOOP.
  ENDLOOP.

* ----------------------------------------------------------------------
* 4. Build border and separator lines
* ----------------------------------------------------------------------
  " Top/Bottom border: +---+---+
  lv_border = ``.
  LOOP AT lt_col_info INTO ls_col_info.
    lv_width = ls_col_info-max_width + 2.
    lv_dashes = repeat( val = `-` occ = lv_width ).
    lv_border = lv_border && `+` && lv_dashes.
  ENDLOOP.
  lv_border = lv_border && `+`.

  " Header separator: |---+---|
  lv_separator = ``.
  lv_col_index = 0.
  LOOP AT lt_col_info INTO ls_col_info.
    lv_col_index = lv_col_index + 1.
    lv_width = ls_col_info-max_width + 2.
    lv_dashes = repeat( val = `-` occ = lv_width ).
    IF lv_col_index = 1.
      lv_separator = `|` && lv_dashes.
    ELSE.
      lv_separator = lv_separator && `+` && lv_dashes.
    ENDIF.
  ENDLOOP.
  lv_separator = lv_separator && `|`.

* ----------------------------------------------------------------------
* 5. Build header row with aligned column names
* ----------------------------------------------------------------------
  lv_line = ``.
  LOOP AT lt_col_info INTO ls_col_info.
    IF ls_col_info-is_numeric = abap_true.
      lv_cell = |{ ls_col_info-display_name WIDTH = ls_col_info-max_width ALIGN = RIGHT }|.
    ELSE.
      lv_cell = |{ ls_col_info-display_name WIDTH = ls_col_info-max_width ALIGN = LEFT }|.
    ENDIF.
    lv_line = lv_line && `| ` && lv_cell && ` `.
  ENDLOOP.
  lv_line = lv_line && `|`.

* ----------------------------------------------------------------------
* 6. Assemble final output: border + header + separator + data + border
* ----------------------------------------------------------------------
  ev_text_table = lv_border && lv_newline
              && lv_line && lv_newline
              && lv_separator.

  " Append each data row with padded and aligned cell values
  LOOP AT it_data ASSIGNING .
    lv_line = ``.
    LOOP AT lt_col_info INTO ls_col_info.
      ASSIGN COMPONENT ls_col_info-name OF STRUCTURE  TO .
      IF sy-subrc = 0.
        TRY.
            lv_field_value = .
          CATCH cx_root.
            CLEAR lv_field_value.
        ENDTRY.
        CONDENSE lv_field_value.
      ELSE.
        CLEAR lv_field_value.
      ENDIF.

      IF ls_col_info-is_numeric = abap_true.
        lv_cell = |{ lv_field_value WIDTH = ls_col_info-max_width ALIGN = RIGHT }|.
      ELSE.
        lv_cell = |{ lv_field_value WIDTH = ls_col_info-max_width ALIGN = LEFT }|.
      ENDIF.
      lv_line = lv_line && `| ` && lv_cell && ` `.
    ENDLOOP.
    lv_line = lv_line && `|`.
    ev_text_table = ev_text_table && lv_newline && lv_line.
  ENDLOOP.

  " Close with bottom border
  ev_text_table = ev_text_table && lv_newline && lv_border.

ENDFUNCTION.

Example


types : begin of ts_abap_version,
          version  type text20,
          year     type char4,
          platform type text20,
        end of ts_abap_version.

data: lt_data       type standard table of ts_abap_version,
      ls_data       type ts_abap_version,
      ev_text_table type string.

ls_data-version  = 'ABAP/4'.
ls_data-year     = '1983'.
ls_data-platform = 'SAP R/2'.
append ls_data to lt_data. clear ls_data.

ls_data-version  = 'ABAP R/3'.
ls_data-year     = '1992'.
ls_data-platform = 'SAP R/3'.
append ls_data to lt_data. clear ls_data.

ls_data-version  = 'ABAP Objects'.
ls_data-year     = '1999'.
ls_data-platform = 'R/3 4.6'.
append ls_data to lt_data. clear ls_data.

ls_data-version  = 'ABAP 7.0'.
ls_data-year     = '2006'.
ls_data-platform = 'NetWeaver 7.0'.
append ls_data to lt_data. clear ls_data.

ls_data-version  = 'ABAP Platform 2020+'.
ls_data-year     = '2020'.
ls_data-platform = 'S/4HANA 2020+'.
append ls_data to lt_data. clear ls_data.

ls_data-version  = 'ABAP 2505 (Cloud)'.
ls_data-year     = '2025'.
ls_data-platform = 'SAP BTP / Cloud'.
append ls_data to lt_data. clear ls_data.

call function 'ZABAP2TEXTTABLE'
  exporting
    it_data          = lt_data
  importing
    ev_text_table    = ev_text_table
  exceptions
    conversion_error = 1
    others           = 2.

if sy-subrc <> 0.
* Implement suitable error handling here
endif.

Output

+---------------------+------+-----------------+
| version             | year | platform        |
|---------------------+------+-----------------|
| ABAP/4              | 1983 | SAP R/2         |
| ABAP R/3            | 1992 | SAP R/3         |
| ABAP Objects        | 1999 | R/3 4.6         |
| ABAP 7.0            | 2006 | NetWeaver 7.0   |
| ABAP Platform 2020+ | 2020 | S/4HANA 2020+   |
| ABAP 2505 (Cloud)   | 2025 | SAP BTP / Cloud |
+---------------------+------+-----------------+