[ABAP] XLSX-Datei mit Klasse cl_ehfnd_xlsx einlesen und in SALV-Grid anzeigen

TRY.
    DATA: lv_rc TYPE i.
    DATA: it_files TYPE filetable.
    DATA: lv_action TYPE i.

* FileOpen-Dialog aufrufen
    cl_gui_frontend_services=>file_open_dialog( EXPORTING file_filter = |xlsx (*.xlsx)\|*.xlsx\|{ cl_gui_frontend_services=>filetype_all }|
                                                CHANGING  file_table  = it_files
                                                          rc          = lv_rc
                                                          user_action = lv_action ).

    IF lv_action = cl_gui_frontend_services=>action_ok.
* wenn Datei ausgewählt wurde
      IF lines( it_files ) > 0.
* ersten Tabelleneintrag lesen
        DATA: lv_filesize TYPE w3param-cont_len.
        DATA: lv_filetype TYPE w3param-cont_type.
        DATA: it_bin_data TYPE w3mimetabtype.

* Excel-Datei auf Appl. Server hochladen (binary)
        cl_gui_frontend_services=>gui_upload( EXPORTING filename   = |{ it_files[ 1 ]-filename }|
                                                        filetype   = 'BIN'
                                              IMPORTING filelength = lv_filesize
                                              CHANGING  data_tab   = it_bin_data ).

* solix -> xstring
        DATA(lv_bin_data) = cl_bcs_convert=>solix_to_xstring( it_solix = it_bin_data ).

**********************************************************************
* XLSX Handling: Kapselt cl_xlsx_document
**********************************************************************
        DATA(o_excel) = cl_ehfnd_xlsx=>get_instance( ).

* XLSX Workbook (XString --> XML)
        DATA(o_doc) = o_excel->load_doc( iv_file_data = lv_bin_data ).

* XLSX Sheets des Workbooks holen
        DATA(it_sheets) = o_doc->get_sheets( ).

        IF lines( it_sheets ) > 0.
* XLSX Sheet: erste Sheet holen
          DATA(o_sheet) = o_doc->get_sheet_by_id( iv_sheet_id = 1 ).
          DATA(lv_sheet_name) = it_sheets[ 1 ]-name.

* max. Zeilenzahl der Sheet
          DATA(lv_max_rows) = o_sheet->get_last_row_number( ).
          DATA(lv_max_cols) = o_sheet->get_last_column_number_in_row( 1 ).

          IF lv_max_rows > 0 AND lv_max_cols > 0.
* Komponenten (Spalten) der Tabelle --> generische Stringtable bauen
            DATA(it_components) = VALUE cl_abap_structdescr=>component_table( ).

* Überschriften (Header) für ALV-Grid
            DATA(it_colnames) = VALUE stringtab( ).

            DO lv_max_cols TIMES.
* Spaltenbezeichner aus 1. Zeile (Header) der Excel-Tabelle holen
              DATA(lv_col_header) = o_sheet->get_cell_content( iv_row    = 1
                                                               iv_column = sy-index ).

* alle Vorkommen, die nicht [a-zA-Z0-9_] entsprechen, durch '_' ersetzen
              REPLACE ALL OCCURRENCES OF REGEX '([^\w]|[äöüÄÖÜß])+' IN lv_col_header WITH '_'.

* Tabelle mit Überschriften für ALV-Grid füllen
              APPEND lv_col_header TO it_colnames.

* Spalte vom Typ String mit generischem Namen zur Komponententabelle hinzufügen
              APPEND VALUE #( name   = |COL{ sy-index }|
                              type   = cl_abap_elemdescr=>get_string( )
                            ) TO it_components.
            ENDDO.

**********************************************************************
* generische interne Tabelle mit hilfe dynamischer Objekte erzeugen
**********************************************************************
* Strukturdeskriptor für Komponententabelle erzeugen
            DATA(o_struct_desc) = cl_abap_structdescr=>create( it_components ).

* Tabellendeskriptor erzeugen
            DATA(o_table_desc) = cl_abap_tabledescr=>create( p_line_type = o_struct_desc ).

* dynamisches Tabellenobjekt anhand des Tabellendeskriptors erstellen
            DATA: o_table TYPE REF TO data.
            CREATE DATA o_table TYPE HANDLE o_table_desc.

* Feldsymbol auf das Tabellenobjekt vom Typ STANDARD TABLE anlegen
            FIELD-SYMBOLS <table> TYPE STANDARD TABLE.
            ASSIGN o_table->* TO <table>.

* Inhalt (ohne Header) aus XLSX in interne Tabelle schreiben
            DATA(lv_row) = 2.

            DO lv_max_rows - 1 TIMES.
              DATA(lv_col) = 1.

* neue Ausgabezeile anfügen
              APPEND INITIAL LINE TO <table>.

* neue Ausgabezeile holen und Feldsymbol zuweisen
              DATA(lv_lc) = lines( <table> ).
              ASSIGN <table>[ lv_lc ] TO FIELD-SYMBOL(<row>).

              IF <row> IS ASSIGNED.
* für alle Spalten der Tabelle
                DO lv_max_cols TIMES.
* n-te Spalte <col> der akt. Tabellenzeile <row> ermitteln
                  ASSIGN COMPONENT lv_col OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
                  IF <cell> IS ASSIGNED.
* Inhalt der akt. Zelle in die Zelle der internen Tabelle schreiben
                    <cell> = o_sheet->get_cell_content( iv_row    = lv_row
                                                        iv_column = lv_col ).


                  ENDIF.

                  lv_col = lv_col + 1.
                ENDDO.
              ENDIF.

              lv_row = lv_row + 1.
            ENDDO.

**********************************************************************
* Anzeige der gefüllten generischen Tabelle in einem SALV-Grid
**********************************************************************
            TRY.
*             SALV-Table
                DATA: o_salv TYPE REF TO cl_salv_table.

                cl_salv_table=>factory( IMPORTING r_salv_table = o_salv
                                        CHANGING  t_table      = <table> ).

*             Grundeinstellungen
                o_salv->get_functions( )->set_all( abap_true ).
                o_salv->get_columns( )->set_optimize( abap_true ).
                o_salv->get_display_settings( )->set_list_header( CONV #( lv_sheet_name ) ).
                o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
                o_salv->get_selections( )->set_selection_mode( if_salv_c_selection_mode=>row_column ).

*             Spaltenüberschriften: technischer Name und Beschreibungstexte, Short Text und Medium Text leer lassen für Autosize
                LOOP AT o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
                  DATA(lv_idx) = sy-tabix.

                  DATA(o_col) = <c>-r_column.
                  o_col->set_short_text( || ).
                  o_col->set_medium_text( || ).
                  o_col->set_long_text( CONV #( it_colnames[ lv_idx ] ) ).
                ENDLOOP.

                o_salv->display( ).
              CATCH cx_root INTO DATA(e_txt).
                WRITE: / e_txt->get_text( ).
            ENDTRY.
          ENDIF.

        ENDIF.

      ENDIF.

    ENDIF.

  CATCH cx_root INTO DATA(e_text).
    MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.

[ABAP] RTTI / RTTC / RTTS: Verwendung von Typdescriptoren

Datenelement

DATA(lv_i) = 1.
DATA(o_elem_desc) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_i ) ).
cl_demo_output=>write_data( o_elem_desc->kind ).
cl_demo_output=>write_data( o_elem_desc->type_kind ).
cl_demo_output=>write_data( o_elem_desc->output_length ).
cl_demo_output=>display( ).

Struct

DATA(lv_struct) = VALUE rsdsselopt( ).
DATA(o_struct_desc) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( lv_struct ) ).
cl_demo_output=>write_data( o_struct_desc->kind ).
cl_demo_output=>write_data( o_struct_desc->components ).
cl_demo_output=>display( ).

Table

DATA(lv_table) = VALUE rseloption( ).
DATA(o_table_desc) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( lv_table ) ).
DATA(o_tl_struct_desc) = CAST cl_abap_structdescr( o_table_desc->get_table_line_type( ) ).
cl_demo_output=>write_data( o_table_desc->kind ).
cl_demo_output=>write_data( o_table_desc->table_kind ).
cl_demo_output=>write_data( o_tl_struct_desc->kind ).
cl_demo_output=>write_data( o_tl_struct_desc->components ).
cl_demo_output=>display( ).

Klasse

DATA(o_class) = NEW cl_abap_codepage( ).
DATA(o_class_desc) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_object_ref( o_class ) ).
cl_demo_output=>write_data( o_class_desc->kind ).
LOOP AT o_class_desc->methods ASSIGNING FIELD-SYMBOL(<m>).
  cl_demo_output=>write( <m>-name ).
ENDLOOP.
cl_demo_output=>display( ).

Interface

DATA(o_if_desc) = CAST cl_abap_intfdescr( cl_abap_typedescr=>describe_by_name( 'IF_RANDOM_NUMBER' ) ).
cl_demo_output=>write_data( o_if_desc->kind ).
LOOP AT o_if_desc->methods ASSIGNING FIELD-SYMBOL(<i>).
  cl_demo_output=>write( <i>-name ).
ENDLOOP.
cl_demo_output=>display( ).

Referenz

DATA(lv_i10) = 10.
DATA(o_ref) = REF #( lv_i10 ).
DATA(o_ref_desc) = CAST cl_abap_refdescr( cl_abap_typedescr=>describe_by_data( o_ref ) ).
cl_demo_output=>write_data( o_ref_desc->kind ).
cl_demo_output=>write_data( o_ref_desc->type_kind ).
cl_demo_output=>write_data( o_ref_desc->absolute_name ).
cl_demo_output=>display( ).

Enumerator

TYPES: BEGIN OF ENUM e_drive_mode BASE TYPE symsgty,
         unknown  VALUE IS INITIAL,
         forward  VALUE 'F',
         backward VALUE 'B',
       END OF ENUM e_drive_mode.

DATA(lv_enum) = VALUE e_drive_mode( ).
DATA(o_enum_desc) = CAST cl_abap_enumdescr( cl_abap_typedescr=>describe_by_data( lv_enum ) ).
cl_demo_output=>write_data( o_enum_desc->kind ).
cl_demo_output=>write_data( o_enum_desc->type_kind ).
cl_demo_output=>write_data( o_enum_desc->base_type_kind ).
cl_demo_output=>write_data( o_enum_desc->members ).
cl_demo_output=>display( ).

Links

[ABAP] IDoc: Strukturen der IDoc-Segmente in eine interne Tabelle lesen

* http://thinkdoforward.com/sap-idoc-tabellen-erfahrene-berater-kennen-diese-tabellen/

* Tabellen: EDIDC   – Kontrollsatz (IDoc)
*           EDIDS   – Statussatz (IDoc)
*           EDID4   – IDoc-Datensätze ab 4.0
*           EDISDEF - IDoc Entwicklung : IDoc Segmentdefinitionen
*           EDSAPPL - EDI: IDoc-Segment Anwendungsstruktur
*           EDIMSGT - Kurzbeschreibung der SAP Nachrichtentypen

TYPES: BEGIN OF ty_idoc_seg_entry,
         seg_name  TYPE string,
         comp_name TYPE string,
         value     TYPE string,
       END OF ty_idoc_seg_entry.

* IDoc-Nummer
PARAMETERS: p_idoc TYPE edidc-docnum DEFAULT '12345'.

START-OF-SELECTION.

* Lesen Segmentdaten des IDocs
  SELECT *
    INTO TABLE @DATA(it_int_edid)
    FROM edid4
    WHERE docnum EQ @p_idoc.

  IF sy-subrc = 0.
* Tabelle für aufbereitete Segmentdaten
    DATA: it_segment_data TYPE STANDARD TABLE OF ty_idoc_seg_entry WITH DEFAULT KEY.

* all. Feldsymbol für Umwandlung der Daten
    FIELD-SYMBOLS: <seg_data> TYPE any.

* Segmentdaten auslesen
    LOOP AT it_int_edid ASSIGNING FIELD-SYMBOL(<s>).
* Typecast für Umwandlung LCHR -> Type
      ASSIGN <s>-sdata TO <seg_data> CASTING TYPE (<s>-segnam).

* Typedescriptor zum Auslesen der einzelnen Datenfelder
      DATA(o_type) = cl_abap_typedescr=>describe_by_data( <seg_data> ).

      CASE o_type->kind.
* wenn Strukturtyp
        WHEN cl_abap_typedescr=>kind_struct.
          DATA(o_desc) = CAST cl_abap_structdescr( o_type ).

* Datenfelder der Struktur durchloopen
          LOOP AT o_desc->get_components( ) ASSIGNING FIELD-SYMBOL(<c>).
* Wert des Feldes auslesen
            ASSIGN COMPONENT <c>-name OF STRUCTURE <seg_data> TO FIELD-SYMBOL(<val>).
            IF <val> IS ASSIGNED.
* Zeile für Segment erstellen mit Segmentname, Komponenten-(Feld-)name, Wert
              APPEND VALUE #( seg_name  = <s>-segnam
                              comp_name = <c>-name
                              value     = <val>
                            ) TO it_segment_data.
            ENDIF.
          ENDLOOP.

        WHEN OTHERS.

      ENDCASE.
    ENDLOOP.

* Datenausgabe
    cl_demo_output=>display( it_segment_data ).
  ENDIF.

[ABAP] RTTS: Interne Tabelle dynamisch erzeugen

Variante 1 (aus DDIC-Struktur)

TRY.
* Strukturdeskriptor für Komponenten (Spalten) der Tabelle anhand einer vorhandenen Struktur erzeugen
    DATA(o_struct_desc) = cl_abap_structdescr=>describe_by_name( 'SFLIGHTS' ).

* Tabellendeskriptor
    DATA(o_table_desc) = cl_abap_tabledescr=>create(
                                                     p_line_type  = CAST #( o_struct_desc )           " Spalten
                                                     p_table_kind = cl_abap_tabledescr=>tablekind_std " Tabellentyp STANDARD TABLE
                                                     p_unique     = abap_false                        " NON-UNIQUE KEY
                                                   ).

* Tabellenobjekt anhand des Tabellendeskriptors erstellen
    DATA: o_table TYPE REF TO data.
    CREATE DATA o_table TYPE HANDLE o_table_desc.

* Feldsymbol auf das Tabellenobjekt
    FIELD-SYMBOLS <table> TYPE ANY TABLE.
    ASSIGN o_table->* TO <table>.

* Daten holen und in Feldsymbol schreiben
    SELECT carrid, connid, carrname, fldate FROM sflights INTO CORRESPONDING FIELDS OF TABLE @<table>.

* Datenausgabe
    cl_demo_output=>display( <table> ).

  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

Variante 2 (eigene Strukturkomponenten)

TRY.
* Dummy für Datadescriptor
    DATA: lv_fldate TYPE sflights-fldate.

* Komponenten (Spalten) der Tabelle
    DATA(it_components) = VALUE cl_abap_structdescr=>component_table(
* Erzeugung über direkte Typangabe, abgeleitet aus dem Typ des eigentlichen Datenelements
* CHAR 3
                                                                      (
                                                                        name = 'CARRID'
                                                                        type = cl_abap_elemdescr=>get_c( 3 ) " S_CARR_ID
                                                                      )
* NUMC 4
                                                                      (
                                                                        name = 'CONNID'
                                                                        type = cl_abap_elemdescr=>get_n( 4 ) " S_CONN_ID
                                                                      )
* Erzeugung über Namen des Datenelements
                                                                      (
                                                                        name = 'CARRNAME'
                                                                        type = CAST #( cl_abap_elemdescr=>describe_by_name( 'S_CARRNAME' ) )
                                                                      )
* Erzeugung über Dummy-Datenobjekt
                                                                      (
                                                                        name = 'FLDATE'
                                                                        type = cast #( cl_abap_datadescr=>describe_by_data( lv_fldate ) )
                                                                      )
                                                                    ).

* Strukturdeskriptor für Komponententabelle
    DATA(o_struct_desc) = cl_abap_structdescr=>create( it_components ).

* Tabellendeskriptor
    DATA(o_table_desc) = cl_abap_tabledescr=>create(
                                                     p_line_type  = o_struct_desc                       " Spalten
                                                     p_table_kind = cl_abap_tabledescr=>tablekind_std   " Tabellentyp STANDARD TABLE
                                                     p_unique     = abap_false                          " NON-UNIQUE KEY
                                                     p_key        = VALUE #(                            " CARRID, CONNID als KEY
                                                                             ( name = 'CARRID' )
                                                                             ( name = 'CONNID' )
                                                                           )
                                                     p_key_kind   = cl_abap_tabledescr=>keydefkind_user " Benutzerdefinierter Schlüssel
                                                   ).

* Tabellenobjekt anhand des Tabellendeskriptors erstellen
    DATA: o_table TYPE REF TO data.
    CREATE DATA o_table TYPE HANDLE o_table_desc.

* Feldsymbol auf das Tabellenobjekt
    FIELD-SYMBOLS <table> TYPE ANY TABLE.
    ASSIGN o_table->* TO <table>.

* Daten holen und in Feldsymbol schreiben
    SELECT carrid, connid, carrname, fldate FROM sflights INTO CORRESPONDING FIELDS OF TABLE @<table>.

* Datenausgabe
    cl_demo_output=>display( <table> ).

  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

[ABAP] ABAP2XLSX: Interne Tabelle als Excel-Datei (*.xlsx) aufbereiten und mit Desktop Office Integration (DOI) als Excel inplace anzeigen

Variante 1 (Daten aus der Tabelle SFLIGHT anzeigen)

* Dummy-Screen für cl_gui_container=>default_screen deklarieren
SELECTION-SCREEN BEGIN OF SCREEN 100.
SELECTION-SCREEN END OF SCREEN 100.

START-OF-SELECTION.

* Daten holen
  SELECT * FROM sflight INTO TABLE @DATA(it_sflight).

  TRY.
* ABAP2XLSX
      DATA: o_xl TYPE REF TO zcl_excel.

* Converter itab->ABAP2XLSX
      DATA(o_converter) = NEW zcl_excel_converter( ).

      o_converter->convert( EXPORTING
                              it_table = it_sflight
                            CHANGING
                              co_excel = o_xl ).

* aktive Worksheet
      DATA(o_xl_ws) = o_xl->get_active_worksheet( ).
* oberste Zeile einfrieren -> beim Scrollen immer sichtbar
      o_xl_ws->freeze_panes( ip_num_rows = 1 ).

* Binärdaten (xstring) generieren
      DATA(o_xlwriter) = CAST zif_excel_writer( NEW zcl_excel_writer_2007( ) ).
      DATA(lv_xl_xdata) = o_xlwriter->write_file( o_xl ).

* Daten mit DOI (Excel inplace) anzeigen
      DATA: o_oic TYPE REF TO i_oi_container_control.
      DATA: o_oid TYPE REF TO i_oi_document_proxy.
      DATA: o_err TYPE REF TO i_oi_error.
      DATA: it_errors TYPE STANDARD TABLE OF REF TO i_oi_error WITH NON-UNIQUE DEFAULT KEY.

      c_oi_container_control_creator=>get_container_control( IMPORTING
                                                               control = o_oic
                                                               error   = o_err ).

      APPEND o_err TO it_errors.

      IF abap_true = o_err->has_succeeded.
        o_oic->init_control( EXPORTING
                               inplace_enabled     = abap_true
                               no_flush            = abap_true
                               r3_application_name = 'Flugverbindungen'
                               parent              = cl_gui_container=>default_screen
                             IMPORTING
                               error               = o_err ).

        APPEND o_err TO it_errors.

        IF abap_true = o_err->has_succeeded.
          o_oic->get_document_proxy( EXPORTING
                                       document_type  = soi_doctype_excel_sheet " 'Excel.Sheet'
                                     IMPORTING
                                       document_proxy = o_oid
                                       error          = o_err ).
          APPEND o_err TO it_errors.

          IF abap_true = o_err->has_succeeded.
            DATA(it_raw) = cl_bcs_convert=>xstring_to_solix( iv_xstring = lv_xl_xdata ).
            DATA(lv_rawlen) = xstrlen( lv_xl_xdata ).

* Binärdaten des *.xlsx im Hintergrund an DOI-Objekt senden und anzeigen
            o_oid->open_document_from_table( EXPORTING
                                               document_size  = lv_rawlen
                                               document_table = it_raw
                                               open_inplace   = abap_true
                                             IMPORTING
                                               error          = o_err ).

            APPEND o_err TO it_errors.

            IF abap_true = o_err->has_succeeded.

* leere Toolbar ausblenden
              cl_abap_list_layout=>suppress_toolbar( ).

* cl_gui_container=>default_screen erzwingen
              CALL SCREEN 100.

* Schließen eines Dokuments in der Office-Anwendung
              o_oid->close_document( IMPORTING error = o_err ).

              APPEND o_err TO it_errors.

              IF o_err->has_succeeded = abap_true.

* Schließen eines Visual-Basic-Dokuments
                o_oid->close_activex_document( IMPORTING error = o_err ).

                APPEND o_err TO it_errors.

                IF o_err->has_succeeded = abap_true.

* Freigabe des für das Dokument reservierten Speichers
                  o_oid->release_document( IMPORTING error = o_err ).

                  APPEND o_err TO it_errors.

                  IF o_err->has_succeeded = abap_true.
                    FREE: o_oid.
                  ENDIF.
                ENDIF.
              ENDIF.
            ENDIF.

* baut das Control ab
            o_oic->destroy_control( IMPORTING error = o_err ).

            APPEND o_err TO it_errors.

            IF o_err->has_succeeded = abap_true.
              FREE: o_oic.
            ENDIF.

          ENDIF.
        ENDIF.
      ENDIF.

* Ausgabe Fehlerprotokoll
      DATA: lv_message_id TYPE sy-msgid.
      DATA: lv_message_number TYPE sy-msgno.
      DATA: lv_param1 TYPE sy-msgv1.
      DATA: lv_param2 TYPE sy-msgv2.
      DATA: lv_param3 TYPE sy-msgv3.
      DATA: lv_param4 TYPE sy-msgv4.

      LOOP AT it_errors ASSIGNING FIELD-SYMBOL(<e>).
        <e>->get_message( IMPORTING
                            message_id     = lv_message_id
                            message_number = lv_message_number
                            param1         = lv_param1
                            param2         = lv_param2
                            param3         = lv_param3
                            param4         = lv_param4
                        ).
        WRITE: / <e>->error_code, lv_message_id, lv_message_number, lv_param1, lv_param2, lv_param3, lv_param4.
      ENDLOOP.

    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

Variante 2 (Daten aus der Tabelle SFLIGHT anzeigen, Styles festlegen)

* Dummy-Screen für cl_gui_container=>default_screen deklarieren
SELECTION-SCREEN BEGIN OF SCREEN 100.
SELECTION-SCREEN END OF SCREEN 100.

START-OF-SELECTION.

* Daten holen
  SELECT * FROM sflight INTO TABLE @DATA(it_sflight).

  TRY.
* ABAP2XLSX
      DATA(o_xl) = NEW zcl_excel( ).
* aktive Worksheet
      DATA(o_xl_ws) = o_xl->get_active_worksheet( ).
* Name der Sheet
      o_xl_ws->set_title( ip_title = 'Flights' ).

* Tabelle übergeben und Style festlegen
      o_xl_ws->bind_table( ip_table          = it_sflight
                           is_table_settings = VALUE #(
                                                        table_style      = zcl_excel_table=>builtinstyle_medium2
*                                                  show_row_stripes = abap_true
                                                      )
                         ).

* oberste Zeile einfrieren -> beim Scrollen immer sichtbar
      o_xl_ws->freeze_panes( ip_num_rows = 1 ).

* Binärdaten (xstring) generieren
      DATA(o_xlwriter) = CAST zif_excel_writer( NEW zcl_excel_writer_2007( ) ).
      DATA(lv_xl_xdata) = o_xlwriter->write_file( o_xl ).

* Daten mit DOI (Excel inplace) anzeigen
      DATA: o_oic TYPE REF TO i_oi_container_control.
      DATA: o_oid TYPE REF TO i_oi_document_proxy.
      DATA: o_err TYPE REF TO i_oi_error.
      DATA: it_errors TYPE STANDARD TABLE OF REF TO i_oi_error WITH NON-UNIQUE DEFAULT KEY.

      c_oi_container_control_creator=>get_container_control( IMPORTING
                                                               control = o_oic
                                                               error   = o_err ).

      APPEND o_err TO it_errors.

      IF abap_true = o_err->has_succeeded.
        o_oic->init_control( EXPORTING
                               inplace_enabled     = abap_true
                               no_flush            = abap_true
                               r3_application_name = 'Flugverbindungen'
                               parent              = cl_gui_container=>default_screen
                             IMPORTING
                               error               = o_err ).

        APPEND o_err TO it_errors.

        IF abap_true = o_err->has_succeeded.
          o_oic->get_document_proxy( EXPORTING
                                       document_type  = soi_doctype_excel_sheet " 'Excel.Sheet'
                                     IMPORTING
                                       document_proxy = o_oid
                                       error          = o_err ).

          APPEND o_err TO it_errors.

          IF abap_true = o_err->has_succeeded.
            DATA(it_raw) = cl_bcs_convert=>xstring_to_solix( iv_xstring = lv_xl_xdata ).
            DATA(lv_rawlen) = xstrlen( lv_xl_xdata ).

* Binärdaten des *.xlsx im Hintergrund an DOI-Objekt senden und anzeigen
            o_oid->open_document_from_table( EXPORTING
                                               document_size    = lv_rawlen
                                               document_table   = it_raw
                                               open_inplace     = abap_true
                                             IMPORTING
                                               error          = o_err ).

            APPEND o_err TO it_errors.

            IF abap_true = o_err->has_succeeded.

* leere Toolbar ausblenden
              cl_abap_list_layout=>suppress_toolbar( ).

* cl_gui_container=>default_screen erzwingen
              CALL SCREEN 100.

* Schließen eines Dokuments in der Office-Anwendung
              o_oid->close_document( IMPORTING error = o_err ).

              APPEND o_err TO it_errors.

              IF o_err->has_succeeded = abap_true.

* Schließen eines Visual-Basic-Dokuments
                o_oid->close_activex_document( IMPORTING error = o_err ).

                APPEND o_err TO it_errors.

                IF o_err->has_succeeded = abap_true.

* Freigabe des für das Dokument reservierten Speichers
                  o_oid->release_document( IMPORTING error = o_err ).

                  APPEND o_err TO it_errors.

                  IF o_err->has_succeeded = abap_true.
                    FREE: o_oid.
                  ENDIF.
                ENDIF.
              ENDIF.
            ENDIF.

* baut das Control ab
            o_oic->destroy_control( IMPORTING error = o_err ).

            APPEND o_err TO it_errors.

            IF o_err->has_succeeded = abap_true.
              FREE: o_oic.
            ENDIF.

          ENDIF.
        ENDIF.
      ENDIF.

* Ausgabe Fehlerprotokoll
      DATA: lv_message_id TYPE sy-msgid.
      DATA: lv_message_number TYPE sy-msgno.
      DATA: lv_param1 TYPE sy-msgv1.
      DATA: lv_param2 TYPE sy-msgv2.
      DATA: lv_param3 TYPE sy-msgv3.
      DATA: lv_param4 TYPE sy-msgv4.

      LOOP AT it_errors ASSIGNING FIELD-SYMBOL(<e>).
        <e>->get_message( IMPORTING
                            message_id     = lv_message_id
                            message_number = lv_message_number
                            param1         = lv_param1
                            param2         = lv_param2
                            param3         = lv_param3
                            param4         = lv_param4
                        ).
        WRITE: / <e>->error_code, lv_message_id, lv_message_number, lv_param1, lv_param2, lv_param3, lv_param4.
      ENDLOOP.

    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

Variante 3 (Daten aus der Tabelle SFLIGHT anzeigen, Komplexbeispiel)

* Dummy-Screen für cl_gui_container=>default_screen deklarieren
SELECTION-SCREEN BEGIN OF SCREEN 100.
SELECTION-SCREEN END OF SCREEN 100.

START-OF-SELECTION.

* Daten holen
  SELECT * FROM sflight INTO TABLE @DATA(it_sflight).

  TRY.
* ABAP2XLSX
      DATA(o_xl) = NEW zcl_excel( ).
* aktive Worksheet
      DATA(o_xl_ws) = o_xl->get_active_worksheet( ).
* Name der Sheet
      o_xl_ws->set_title( ip_title = 'Flights' ).
* Gitterlinien ausschalten
      o_xl_ws->set_show_gridlines( i_show_gridlines = abap_false ).
* oberste zwei Zeilen einfrieren -> beim Scrollen immer sichtbar
      o_xl_ws->freeze_panes( ip_num_rows = 2 ).

* RTTS: Table: Beschreibung
      DATA(o_tdesc) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data( it_sflight ) ).
* RTTS: Row: Beschreibung
      DATA(o_sdesc) = CAST cl_abap_structdescr( o_tdesc->get_table_line_type( ) ).
* RTTS: Col: Komponenten (Felder) -> DFIES: DD-Schnittstelle: Tabellenfelder für DDIF_FIELDINFO_GET
      DATA(it_com) = o_sdesc->get_components( ).

* Header einfügen
      LOOP AT it_com ASSIGNING FIELD-SYMBOL(<c>).
        DATA(lv_col_head) = sy-tabix.
* Prüfen, ob DDIC-Typ, damit die Metadaten ausgelesen werden können
        DATA(o_edesc_head) = CAST cl_abap_elemdescr( <c>-type ).
        IF o_edesc_head->is_ddic_type( ) EQ abap_true.
          DATA(lv_dfies_head) = o_edesc_head->get_ddic_field( ).
* technischer Name in die erste Zeile
          o_xl_ws->set_cell( ip_column = lv_col_head
                             ip_row    = 1
                             ip_value  = <c>-name ).
* Langtext des Feldes in die zweite Zeile
          o_xl_ws->set_cell( ip_column = lv_col_head
                             ip_row    = 2
                             ip_value  = lv_dfies_head-scrtext_l ).

* Spaltenbreite setzen
          o_xl_ws->get_column( lv_col_head )->set_width( strlen( lv_dfies_head-scrtext_l ) + 5 ).
        ENDIF.

      ENDLOOP.

* Daten einfügen
      LOOP AT it_sflight ASSIGNING FIELD-SYMBOL(<row>).
        DATA(lv_row) = sy-tabix + 2.

        LOOP AT it_com ASSIGNING FIELD-SYMBOL(<col>).
          DATA(lv_col) = sy-tabix.

* Prüfen, ob DDIC-Typ, damit die Metadaten ausgelesen werden können
          DATA(o_edesc) = CAST cl_abap_elemdescr( <col>-type ).
          IF o_edesc->is_ddic_type( ) EQ abap_true.
* wenn DDIC-Typ, dann Metainformationen auslesen
            DATA(lv_dfies) = o_edesc->get_ddic_field( ).
* anhand des Komponentennamens den akt. Zellinhalt einer Zeile lesen
            ASSIGN COMPONENT <col>-name OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
            IF <cell> IS ASSIGNED.
              o_xl_ws->set_cell( ip_column = lv_col
                                 ip_row    = lv_row
                                 ip_value  = <cell> ).
            ENDIF.
          ENDIF.
        ENDLOOP.

* Zeilenhöhe
        o_xl_ws->get_row( ip_row = lv_row )->set_row_height( 15 ).
      ENDLOOP.

* Autofilter setzen
      DATA(o_autofilter) = o_xl->add_new_autofilter( io_sheet = o_xl_ws ).
      o_autofilter->set_filter_area( is_area = VALUE #( row_start = 2
                                                        col_start = 1
                                                        row_end   = o_xl_ws->get_highest_row( )
                                                        col_end   = o_xl_ws->get_highest_column( ) ) ).

* Binärdaten (xstring) generieren
      DATA(o_xlwriter) = CAST zif_excel_writer( NEW zcl_excel_writer_2007( ) ).
      DATA(lv_xl_xdata) = o_xlwriter->write_file( o_xl ).

* Daten mit DOI (Excel inplace) anzeigen
      DATA: o_oic TYPE REF TO i_oi_container_control.
      DATA: o_oid TYPE REF TO i_oi_document_proxy.
      DATA: o_err TYPE REF TO i_oi_error.
      DATA: it_errors TYPE STANDARD TABLE OF REF TO i_oi_error WITH NON-UNIQUE DEFAULT KEY.

      c_oi_container_control_creator=>get_container_control( IMPORTING
                                                               control = o_oic
                                                               error   = o_err ).

      APPEND o_err TO it_errors.

      IF abap_true = o_err->has_succeeded.
        o_oic->init_control( EXPORTING
                               inplace_enabled     = abap_true
                               no_flush            = abap_true
                               r3_application_name = 'Flugverbindungen'
                               parent              = cl_gui_container=>default_screen
                             IMPORTING
                               error               = o_err ).

        APPEND o_err TO it_errors.

        IF abap_true = o_err->has_succeeded.
          o_oic->get_document_proxy( EXPORTING
                                       document_type  = soi_doctype_excel_sheet " 'Excel.Sheet'
                                     IMPORTING
                                       document_proxy = o_oid
                                       error          = o_err ).

          APPEND o_err TO it_errors.

          IF abap_true = o_err->has_succeeded.
            DATA(it_raw) = cl_bcs_convert=>xstring_to_solix( iv_xstring = lv_xl_xdata ).
            DATA(lv_rawlen) = xstrlen( lv_xl_xdata ).

* Binärdaten des *.xlsx im Hintergrund an DOI-Objekt senden und anzeigen
            o_oid->open_document_from_table( EXPORTING
                                               document_size  = lv_rawlen
                                               document_table = it_raw
                                               open_inplace   = abap_true
                                             IMPORTING
                                               error          = o_err ).

            APPEND o_err TO it_errors.

            IF abap_true = o_err->has_succeeded.
* leere Toolbar ausblenden
              cl_abap_list_layout=>suppress_toolbar( ).

* cl_gui_container=>default_screen erzwingen
              CALL SCREEN 100.

* Schließen eines Dokuments in der Office-Anwendung
              o_oid->close_document( IMPORTING error = o_err ).

              APPEND o_err TO it_errors.

              IF o_err->has_succeeded = abap_true.

* Schließen eines Visual-Basic-Dokuments
                o_oid->close_activex_document( IMPORTING error = o_err ).

                APPEND o_err TO it_errors.

                IF o_err->has_succeeded = abap_true.

* Freigabe des für das Dokument reservierten Speichers
                  o_oid->release_document( IMPORTING error = o_err ).

                  APPEND o_err TO it_errors.

                  IF o_err->has_succeeded = abap_true.
                    FREE: o_oid.
                  ENDIF.
                ENDIF.
              ENDIF.
            ENDIF.

* baut das Control ab
            o_oic->destroy_control( IMPORTING error = o_err ).

            APPEND o_err TO it_errors.

            IF o_err->has_succeeded = abap_true.
              FREE: o_oic.
            ENDIF.

          ENDIF.
        ENDIF.
      ENDIF.

* Ausgabe Fehlerprotokoll
      DATA: lv_message_id TYPE sy-msgid.
      DATA: lv_message_number TYPE sy-msgno.
      DATA: lv_param1 TYPE sy-msgv1.
      DATA: lv_param2 TYPE sy-msgv2.
      DATA: lv_param3 TYPE sy-msgv3.
      DATA: lv_param4 TYPE sy-msgv4.

      LOOP AT it_errors ASSIGNING FIELD-SYMBOL(<e>).
        <e>->get_message( IMPORTING
                            message_id     = lv_message_id
                            message_number = lv_message_number
                            param1         = lv_param1
                            param2         = lv_param2
                            param3         = lv_param3
                            param4         = lv_param4
                        ).
        WRITE: / <e>->error_code, lv_message_id, lv_message_number, lv_param1, lv_param2, lv_param3, lv_param4.
      ENDLOOP.

    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] Zugriff auf die Metainformationen einer internen Tabelle

* Daten holen
SELECT carrid, connid, fldate, price, currency, planetype
  INTO TABLE @DATA(it_sflight)
  FROM sflight .

* Table: Beschreibung
DATA(o_tdesc) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data( it_sflight ) ).
* Row: Beschreibung
DATA(o_sdesc) = CAST cl_abap_structdescr( o_tdesc->get_table_line_type( ) ).
* Col: Komponenten (Felder) -> DFIES: DD-Schnittstelle: Tabellenfelder für DDIF_FIELDINFO_GET
DATA(it_com) = o_sdesc->get_components( ).

* Header
LOOP AT it_com ASSIGNING FIELD-SYMBOL(<c>).
* Prüfen, ob DDIC-Typ, damit die Metadaten ausgelesen werden können
  DATA(o_edesc) = CAST cl_abap_elemdescr( <c>-type ).
  IF o_edesc->is_ddic_type( ) EQ abap_true.
    DATA(lv_dfies) = o_edesc->get_ddic_field( ).
* technischer Name
*    WRITE: |{ <c>-name WIDTH = lv_dfies-scrlen3 }|.
* Langtext des Feldes
    WRITE: |{ lv_dfies-scrtext_l WIDTH = lv_dfies-scrlen3 }|.
  ENDIF.
ENDLOOP.

ULINE.

* Daten zellenweise auslesen
LOOP AT it_sflight ASSIGNING FIELD-SYMBOL(<row>).

  LOOP AT it_com ASSIGNING FIELD-SYMBOL(<col>).
* Prüfen, ob DDIC-Typ, damit die Metadaten ausgelesen werden können
    DATA(o_edesc2) = CAST cl_abap_elemdescr( <col>-type ).
    IF o_edesc2->is_ddic_type( ) EQ abap_true.
* wenn DDIC-Typ, dann Metainformationen auslesen
      DATA(lv_dfies2) = o_edesc2->get_ddic_field( ).
* anhand des Komponentennamens den akt. Zellinhalt einer Zeile lesen
      ASSIGN COMPONENT <col>-name OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
      WRITE: |{ <cell> WIDTH = lv_dfies2-scrlen3 }|.
    ENDIF.
  ENDLOOP.

  WRITE: /.

ENDLOOP.

[ABAP] Interne Tabellen im Format Office Open XML (SpreadsheetML) speichern

Beispiel für die Nutzung des Office Open XML (SpreadsheetML) Formates zur Datenausgabe von Nutzdaten aus internen Tabellen.

Links

Wikipedia – Office Open XML
Wikipedia – SpreadsheetML
SAP ABAP Doku
Beispiel 1
Beispiel 2

Beispiel – Speicherung Daten beliebiger interner Tabellen in eine von Microsoft Office Excel lesbare XML-Datei

* Dateien können ab Microsoft Office Excel 2002 / 2003 geöffnet werden
DATA: it_spfli TYPE STANDARD TABLE OF spfli.
DATA: gv_company TYPE string VALUE 'codezentrale.de'.
DATA: gv_user TYPE string VALUE 'Testuser'.
DATA: gv_sheetname TYPE string VALUE 'SPFLI'.

INITIALIZATION.
* Daten holen
  SELECT * FROM spfli INTO TABLE @it_spfli.

START-OF-SELECTION.

  DATA: o_cell TYPE REF TO if_ixml_element.
  DATA: o_data TYPE REF TO if_ixml_element.

* Tabellenstruktur
  DATA(o_table_descr) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data( it_spfli ) ).

* Struktur einer Tabellenzeile
  DATA(o_struct_descr) = CAST cl_abap_structdescr( o_table_descr->get_table_line_type( ) ).

* Komponenten (Spalten) einer Zeile
  DATA(it_comp_tab) = o_struct_descr->get_components( ).

* Anzahl Spalten
  DATA(lv_colcount) = lines( it_comp_tab ).

* ixml Factory
  DATA(o_ixml) = cl_ixml=>create( ).

* Encoding UTF-8
  DATA(o_encoding) = o_ixml->create_encoding( character_set = 'UTF-8'
                                              byte_order = if_ixml_encoding=>co_none ).

* DOM Object Model
  DATA(o_doc) = o_ixml->create_document( ).

* Processing Instructions setzen
* damit die XML-Datei gleich vom Windows als Excel-XML erkannt und korrekt geöffnet wird
  DATA(o_pi) = o_doc->create_pi_parsed( name = 'mso-application' ).
  o_pi->set_attribute( name = 'progid' value = 'Excel.Sheet' ).
  o_doc->append_child( o_pi ).

* Workbook
  DATA(o_workbook) = o_doc->create_simple_element( name = 'Workbook' parent = o_doc ).
  o_workbook->set_attribute( name = 'xmlns' value ='urn:schemas-microsoft-com:office:spreadsheet' ).
  o_workbook->set_attribute_node( o_doc->create_namespace_decl( name = 'o' prefix = 'xmlns' uri = 'urn:schemas-microsoft-com:office:office') ).
  o_workbook->set_attribute_node( o_doc->create_namespace_decl( name = 'x' prefix = 'xmlns' uri = 'urn:schemas-microsoft-com:office:excel' ) ).
  o_workbook->set_attribute_node( o_doc->create_namespace_decl( name = 'ss' prefix = 'xmlns' uri = 'urn:schemas-microsoft-com:office:spreadsheet') ).
  o_workbook->set_attribute_node( o_doc->create_namespace_decl( name = 'html' prefix = 'xmlns' uri = 'http://www.w3.org/TR/REC-html40') ).

* DocumentProperties
* Zeitstempel erzeugen
  DATA: lv_tsl TYPE timestampl.
  GET TIME STAMP FIELD lv_tsl.
  DATA(lv_created) = |{ substring( val = |{ lv_tsl TIMESTAMP = ISO }| off = 0 len = 19 ) }Z|.

  DATA(o_prop) = o_doc->create_simple_element( name = 'DocumentProperties' parent = o_workbook ).
  o_prop->set_attribute( name = 'xmlns' value ='urn:schemas-microsoft-com:office:office' ).
  o_doc->create_simple_element( name = 'Author' value = gv_user parent = o_prop ).
  o_doc->create_simple_element( name = 'LastAuthor' value = gv_user parent = o_prop ).
  o_doc->create_simple_element( name = 'Created' value = lv_created parent = o_prop ).
  o_doc->create_simple_element( name = 'Company' value = gv_company parent = o_prop ).
  o_doc->create_simple_element( name = 'Version' value = '14.00' parent = o_prop ).

* OfficeDocumentSettings
  DATA(o_set) = o_doc->create_simple_element( name = 'OfficeDocumentSettings' parent = o_workbook ).
  o_set->set_attribute( name = 'xmlns' value ='urn:schemas-microsoft-com:office:office' ).
  o_doc->create_simple_element( name = 'AllowPNG' parent = o_set ).

* ExcelWorkbook
  DATA(o_excelwb) = o_doc->create_simple_element( name = 'ExcelWorkbook' parent = o_workbook ).
  o_excelwb->set_attribute( name = 'xmlns' value ='urn:schemas-microsoft-com:office:excel' ).
  o_doc->create_simple_element( name = 'ProtectStructure' value = 'False' parent = o_excelwb ).
  o_doc->create_simple_element( name = 'ProtectWindows' value = 'False' parent = o_excelwb ).

* Styles
  DATA(o_styles) = o_doc->create_simple_element( name = 'Styles' parent = o_workbook ).

* "Default" Style
  DATA(o_style_default) = o_doc->create_simple_element( name = 'Style' parent = o_styles ).
  o_style_default->set_attribute_ns( name = 'ID' prefix = 'ss' value = 'Default' ).
  o_style_default->set_attribute_ns( name = 'Name' prefix = 'ss' value = 'Normal' ).
  DATA(o_align) = o_doc->create_simple_element( name = 'Alignment' parent = o_style_default ).
  o_align->set_attribute_ns( name = 'Vertical' prefix = 'ss' value = 'Bottom' ).
  DATA(o_borders) = o_doc->create_simple_element( name = 'Borders' parent = o_style_default ).
  DATA(o_font) = o_doc->create_simple_element( name = 'Font' parent = o_style_default ).
  o_font->set_attribute_ns( name = 'FontName' prefix = 'ss' value = 'Arial' ).
  o_font->set_attribute_ns( name = 'Family' prefix = 'x' value = 'Swiss' ).
  o_font->set_attribute_ns( name = 'Size' prefix = 'ss' value = '11' ).
  o_font->set_attribute_ns( name = 'Color' prefix = 'ss' value = '#000000' ).
  DATA(o_interior) = o_doc->create_simple_element( name = 'Interior' parent = o_style_default ).
  DATA(o_numberformat) = o_doc->create_simple_element( name = 'NumberFormat' parent = o_style_default ).
  DATA(o_protection) = o_doc->create_simple_element( name = 'Protection' parent = o_style_default ).

* Bold Style "s62" für die Überschrift
  DATA(o_style_bold) = o_doc->create_simple_element( name = 'Style' parent = o_styles ).
  o_style_bold->set_attribute_ns( name = 'ID' prefix = 'ss' value = 's62' ).
  DATA(o_font_bold) = o_doc->create_simple_element( name = 'Font' parent = o_style_bold ).
  o_font_bold->set_attribute_ns( name = 'FontName' prefix = 'ss' value = 'Arial' ).
  o_font_bold->set_attribute_ns( name = 'Family' prefix = 'x' value = 'Swiss' ).
  o_font_bold->set_attribute_ns( name = 'Size' prefix = 'ss' value = '11' ).
  o_font_bold->set_attribute_ns( name = 'Color' prefix = 'ss' value = '#000000' ).
  o_font_bold->set_attribute_ns( name = 'Bold' prefix = 'ss' value = '1' ).

* Worksheet "SPFLI" einfügen
  DATA(o_sheet1) = o_doc->create_simple_element( name = 'Worksheet' parent = o_workbook ).
  o_sheet1->set_attribute_ns( name = 'Name' prefix = 'ss' value = gv_sheetname ).

* WorksheetOptions
  DATA(o_ws_opt) = o_doc->create_simple_element( name = 'WorksheetOptions' parent = o_sheet1 ).
  o_ws_opt->set_attribute( name = 'xmlns' value = 'urn:schemas-microsoft-com:office:excel' ).

  o_doc->create_simple_element( name = 'Selected' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'ProtectObjects' value = 'False' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'ProtectScenarios' value = 'False' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'SplitHorizontal' value = '1' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'TopRowBottomPane' value = '1' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'FreezePanes' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'FrozenNoSplit' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'Unsynced' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'ActivePane' value = '2' parent = o_ws_opt ).

* Page Setup
  DATA(o_ps) = o_doc->create_simple_element( name = 'PageSetup' parent = o_ws_opt ).
  DATA(o_ps_header) = o_doc->create_simple_element( name = 'Header' parent = o_ps ).
  o_ps_header->set_attribute_ns( name = 'Margin' prefix = 'x' value = '0.3' ).
  DATA(o_ps_footer) = o_doc->create_simple_element( name = 'Footer' parent = o_ps ).
  o_ps_footer->set_attribute_ns( name = 'Margin' prefix = 'x' value = '0.3' ).
  DATA(o_ps_margins) = o_doc->create_simple_element( name = 'PageMargins' parent = o_ps ).
  o_ps_margins->set_attribute_ns( name = 'Bottom' prefix = 'x' value = '0.7' ).
  o_ps_margins->set_attribute_ns( name = 'Left' prefix = 'x' value = '0.7' ).
  o_ps_margins->set_attribute_ns( name = 'Right' prefix = 'x' value = '0.7' ).
  o_ps_margins->set_attribute_ns( name = 'Top' prefix = 'x' value = '0.7' ).

* Splitter für Header / Data definieren
  o_doc->create_simple_element( name = 'x:Selected' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:FreezePanes' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:FrozenNoSplit' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:Unsynced' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:ProtectObjects' value = 'False' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:ProtectScenarios' value = 'False' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:SplitHorizontal' value = '1' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:TopRowBottomPane' value = '1' parent = o_ps ).

* Named Range für Filter definieren
  DATA(o_names) = o_doc->create_simple_element( name = 'Names' parent = o_sheet1 ).
  DATA(o_named_range) = o_doc->create_simple_element( name = 'NamedRange' parent = o_names ).
  o_named_range->set_attribute_ns( name = 'Name' prefix = 'ss' value = '_FilterDatabase' ).
  o_named_range->set_attribute_ns( name = 'RefersTo' prefix = 'ss' value = |=Sheet1!R1C1:R1C{ lv_colcount }| ). " Spalte 1-x als Range "_FilterDatabase" definieren
  o_named_range->set_attribute_ns( name = 'Hidden' prefix = 'ss' value = '1' ).

* Autofilter aktivieren
  DATA(o_autofilter) = o_doc->create_simple_element( name = 'AutoFilter' parent = o_sheet1 ).
  o_autofilter->set_attribute_ns( name = 'Range' prefix = 'x' value = |R1C1:R1C{ lv_colcount }| ).              " Spalte 1-x als Filter-Range definieren
  o_autofilter->set_attribute_ns( name = 'xmlns' value = 'urn:schemas-microsoft-com:office:excel' ).

* Table für Header und Daten
  DATA(o_table) = o_doc->create_simple_element( name = 'Table' parent = o_sheet1 ).
  o_table->set_attribute_ns( name = 'FullColumns' prefix = 'x' value = '1' ).
  o_table->set_attribute_ns( name = 'FullRows' prefix = 'x' value = '1' ).
  o_table->set_attribute_ns( name = 'DefaultColumnWidth' prefix = 'x' value = '66' ).
  o_table->set_attribute_ns( name = 'DefaultRowHeight' prefix = 'x' value = '14.25' ).
  o_table->set_attribute_ns( name = 'DefaultColumnWidth' prefix = 'ss' value = '66' ).
  o_table->set_attribute_ns( name = 'DefaultRowHeight' prefix = 'ss' value = '14.25' ).

* Header (Tabellenüberschriften) einfügen
  DATA(o_hrow) = o_doc->create_simple_element( name = 'Row' parent = o_table ).

  LOOP AT it_comp_tab ASSIGNING FIELD-SYMBOL(<fs_comp>).
    o_cell = o_doc->create_simple_element( name = 'Cell' parent = o_hrow ).
    o_cell->set_attribute_ns( name = 'StyleID' prefix = 'ss' value = 's62' ). " Style Bold
* nur elementare Datentypen zulassen
    IF <fs_comp>-type->kind = cl_abap_typedescr=>kind_elem.
      o_doc->create_simple_element( name = 'Data' value = <fs_comp>-name parent = o_cell )->set_attribute_ns( name = 'Type' prefix = 'ss' value = 'String' ).
    ELSE.
* alle anderen Spalten mit Strukturen, INCLUDES usw. einfach als DEEP kennzeichnen, Inhalt bleibt leer
      o_doc->create_simple_element( name = 'Data' value = 'DEEP' parent = o_cell )->set_attribute_ns( name = 'Type' prefix = 'ss' value = 'String' ).
    ENDIF.
* Named Range "_FilterDatabase" für Filter setzen
    o_doc->create_simple_element( name = 'NamedCell' parent = o_cell )->set_attribute_ns( name = 'Name' prefix = 'ss' value = '_FilterDatabase' ).
  ENDLOOP.

* Daten einfügen
  LOOP AT it_spfli ASSIGNING FIELD-SYMBOL(<fs_line>).
    DATA(o_row_data) = o_doc->create_simple_element( name = 'Row' parent = o_table ).

    o_struct_descr ?= cl_abap_structdescr=>describe_by_data( <fs_line> ).

    LOOP AT o_struct_descr->get_components( ) ASSIGNING FIELD-SYMBOL(<fs_comp2>).

      o_cell = o_doc->create_simple_element( name = 'Cell' parent = o_row_data ).

* nur elementare Datentypen zulassen, andernfalls gibts Exceptions bei der String-Konvertierung
* die Spalten mit kennzeichnung "DEEP" bleiben in der Ausgabe somit leer
      IF <fs_comp2>-type->kind = cl_abap_typedescr=>kind_elem.
        ASSIGN COMPONENT <fs_comp2>-name OF STRUCTURE <fs_line> TO FIELD-SYMBOL(<fs_cell>).

        IF <fs_cell> IS ASSIGNED.
          DATA: lv_data_type TYPE string.
          DATA(lv_typekind) = cl_abap_elemdescr=>get_data_type_kind( <fs_cell> ).

          CASE lv_typekind.
            WHEN cl_abap_typedescr=>typekind_time OR cl_abap_typedescr=>typekind_date OR cl_abap_typedescr=>typekind_string OR cl_abap_typedescr=>typekind_char.
              lv_data_type = 'String'.
            WHEN cl_abap_typedescr=>typekind_num OR cl_abap_typedescr=>typekind_packed OR cl_abap_typedescr=>typekind_int OR cl_abap_typedescr=>typekind_float.
              lv_data_type = 'Number'.
            WHEN OTHERS.
              lv_data_type = 'String'.
          ENDCASE.

          o_data = o_doc->create_simple_element( name = 'Data' value = |{ <fs_cell> }| parent = o_cell ).
          o_data->set_attribute_ns( name = 'Type' prefix = 'ss' value = lv_data_type ).
        ENDIF.
      ENDIF.

    ENDLOOP.
  ENDLOOP.

* XML-Dokument rendern
  DATA(o_sf) = o_ixml->create_stream_factory( ).

  DATA: lv_xml TYPE string.

  DATA(o_stream) = o_sf->create_ostream_cstring( lv_xml ).
  o_stream->set_encoding( encoding = o_encoding ).
  o_stream->set_pretty_print( pretty_print = abap_true ).

  DATA(o_render) = o_ixml->create_renderer( ostream  = o_stream
                                            document = o_doc ).

* XML-String in lv_xml generieren
  DATA(lv_rc) = o_render->render( ).

* Dateigröße in Bytes
  DATA(lv_size) = o_stream->get_num_written_raw( ).

* Stream schließen
  o_stream->close( ).

  IF lv_rc = 0 AND lv_size > 0.
* XML-String in XML-Document wandeln
    DATA(o_xml_doc) = NEW cl_xml_document( ).
    o_xml_doc->parse_string( lv_xml ).

* Ausgabe-Datei, "\" müssen quotiert werden
    DATA(lv_fullpath) = |c:\\temp\\test.xml|.

* XML-Document als Datei speichern
    o_xml_doc->export_to_file( CONV #( lv_fullpath ) ).

* lokale Datei im Excel aufrufen
* parameter muss wegen möglicher Leerzeichen im Pfad mit "" quotiert werden
    cl_gui_frontend_services=>execute( application = 'excel.exe'
                                       parameter = |"{ lv_fullpath }"| ).
  ELSE.
    WRITE: / 'Fehler beim Erzeugen der XML-Datei.'.
  ENDIF.

[ABAP] RTTS verwenden, um Feldnamen und Eigenschaften einer DB-Tabelle anzuzeigen

DATA: o_desc TYPE REF TO cl_abap_structdescr.

o_desc ?= cl_abap_structdescr=>describe_by_name( 'MARA' ).

DATA(o_ddic_fields) = o_desc->get_ddic_field_list( ).

LOOP AT o_ddic_fields INTO DATA(ls_ddfields) WHERE keyflag = 'X'.
  WRITE: / ls_ddfields-fieldname, ls_ddfields-fieldtext.
ENDLOOP.

[ABAP] Generische Verarbeitung von internen Tabellen / Verwendung von Referenzen

* irgendeine interne Tablelle anlegen
DATA: it_tab TYPE STANDARD TABLE OF ...
* generische Tabellenreferenz anlegen
DATA: o_ref_table TYPE REF TO data.
 
...
 
* Tabellenreferenz übergeben
o_ref_table = REF #( it_tab ).
 
* Referenz auf generisches Feldsymbol mappen
FIELD-SYMBOLS: <tab> TYPE ANY TABLE.
ASSIGN o_ref_table->* TO <tab>.
 
* Tabellen-Zeile erzeugen
* muss hier erfolgen, damit man ein "greifbares" Tabellen-Zeilen-Objekt
* für die Strukturermittlung (describe_by_data) hat
DATA: o_row TYPE REF TO data.
CREATE DATA o_row LIKE LINE OF <tab>.
FIELD-SYMBOLS: <row> TYPE any.
ASSIGN o_row->* TO <row>.
 
* Komponenten (Spalten) einer Tabellenzeile ermitteln
DATA(o_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( <row> ) ).
DATA(it_comp_tab) = o_struct->get_components( ).
 
* Anzahl Spalten der Tabellen-Zeile holen
DATA(lv_colcnt) = lines( it_comp_tab ).
 
* Tabelle durchloopen
LOOP AT <tab> ASSIGNING <row>.

* Spalten der akt. Zeile durchgehen
  DO lv_colcnt TIMES.
* Zelle: n-tes Element der akt. Zeile holen
    ASSIGN COMPONENT sy-index OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
    
* Trennzeichen vor die Spalte einfügen, wenn nicht 1. Spalte
    IF sy-index > 1.
      WRITE: '|'.
    ENDIF.

* Achtung: Zell-Typ beachten! Es können hier nur flache Typen (Keine Strukturen, Tabellen) ausgegeben werden, der Rest muss gesondert behandelt werden
    IF CAST cl_abap_elemdescr( it_comp_tab[ sy-index ]-type )->kind = cl_abap_elemdescr=>kind_elem.
* Ausgabe Zellinhalt mit vordefinierter Spaltenbreite
      WRITE: |{ <cell> WIDTH = 20 |.
    ENDIF.
  ENDDO.

  NEW-LINE.
ENDLOOP.