[ABAP] Interne Tabelle als Excel-Datei (*.xlsx) speichern (cl_fdt_xl_spreadsheet)

* Mit Hilfe der Klasse cl_fdt_xl_spreadsheet können über XML-Transformationen
* Daten aus SAP in XLSX-Dateien geschrieben werden
TRY.
* Testdaten lesen
    SELECT * FROM t001 INTO TABLE @DATA(it_t001).

    IF sy-subrc = 0.
* Header erzeugen
      DATA: it_columns TYPE if_fdt_doc_spreadsheet=>t_column.
      DATA: lv_head TYPE t001.
      DATA(o_desc) = CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_data( lv_head ) ).

      LOOP AT o_desc->get_components( ) ASSIGNING FIELD-SYMBOL(<c>).
        IF <c> IS ASSIGNED.
          IF <c>-type->kind = cl_abap_typedescr=>kind_elem.
            APPEND VALUE #( id           = sy-tabix
                            name         = <c>-name
                            display_name = <c>-name
                            is_result    = abap_true
                            type         = <c>-type ) TO it_columns.
          ENDIF.
        ENDIF.
      ENDLOOP.

* itab + header -> XML -> xstring
* Achtung: Speicherintensiv und rel. langsam! Es sollten keine großen Datenmengen verarbeitet werden.
      DATA(lv_bin_data) = cl_fdt_xl_spreadsheet=>if_fdt_doc_spreadsheet~create_document( columns      = it_columns " optional
                                                                                         itab         = REF #( it_t001 )
                                                                                         iv_call_type = if_fdt_doc_spreadsheet=>gc_call_dec_table ).
      IF xstrlen( lv_bin_data ) > 0.
        DATA: lv_action TYPE i.
        DATA: lv_filename TYPE string.
        DATA: lv_fullpath TYPE string.
        DATA: lv_path TYPE string.

* Save-Dialog
        cl_gui_frontend_services=>file_save_dialog( EXPORTING
                                                      default_file_name = 'Excel.xlsx'
                                                      default_extension = 'xlsx'
                                                      file_filter       = |Excel-Datei (*.xlsx)\|*.xlsx\|{ cl_gui_frontend_services=>filetype_all }|
                                                    CHANGING
                                                      filename          = lv_filename
                                                      path              = lv_path
                                                      fullpath          = lv_fullpath
                                                      user_action       = lv_action ).

        IF lv_action EQ cl_gui_frontend_services=>action_ok.
* XSTRING -> SOLIX (RAW)
          DATA(it_raw_data) = cl_bcs_convert=>xstring_to_solix( EXPORTING iv_xstring = lv_bin_data ).

* Datei lokal speichern
          cl_gui_frontend_services=>gui_download( EXPORTING
                                                    filename     = lv_fullpath
                                                    filetype     = 'BIN'
                                                    bin_filesize = xstrlen( lv_bin_data )
                                                  CHANGING
                                                    data_tab     = it_raw_data ).


        ENDIF.
      ENDIF.
    ENDIF.
  CATCH cx_root INTO DATA(e_text).
    MESSAGE e_text->get_text( ) TYPE 'I'.
ENDTRY.

[ABAP] Excel-Datei (*.xlsx) in interne Tabelle laden (cl_fdt_xl_spreadsheet)

Variante 1 (generische Ausgabe mit cl_demo_output)

* Mit Hilfe der Klasse cl_fdt_xl_spreadsheet können über XML-Transformationen
* aus XLSX-Dateien Daten extrahiert und in eine interne Tabelle konvertiert werden
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.

* Bild 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 ).

* Excel (itab) -> XML -> Ref-Objekt
* Achtung: Speicherintensiv und rel. langsam! Es sollten keine großen Datenmengen verarbeitet werden.
        DATA(o_excel) = NEW cl_fdt_xl_spreadsheet( document_name = CONV #( it_files[ 1 ]-filename )
                                                   xdocument     = lv_bin_data ).

        DATA: it_worksheet_names TYPE if_fdt_doc_spreadsheet=>t_worksheet_names.

* Worksheetnamen ermitteln
        o_excel->if_fdt_doc_spreadsheet~get_worksheet_names( IMPORTING worksheet_names = it_worksheet_names ).

        IF lines( it_worksheet_names ) > 0.
* erste Worksheet holen und -> REF to itab erstellen
          DATA(o_worksheet_itab) = o_excel->if_fdt_doc_spreadsheet~get_itab_from_worksheet( it_worksheet_names[ 1 ] ).

* Referenz auf generisches Feldsymbol mappen
          ASSIGN o_worksheet_itab->* TO FIELD-SYMBOL(<worksheet>).

* Datenausgabe
          cl_demo_output=>write_data( <worksheet> ).

* HTML-Daten aus itab generieren
          DATA(lv_html) = cl_demo_output=>get( ).

* Daten im Inline-Browser im SAP-Fenster anzeigen
          cl_abap_browser=>show_html( EXPORTING
                                        title        = 'Excel-Worksheet'
                                        html_string  = lv_html
                                        container    = cl_gui_container=>default_screen ).

* cl_gui_container=>default_screen erzwingen
          WRITE: space.
        ENDIF.
      ENDIF.
    ENDIF.

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

Variante 2 (generische Listausgabe)

TYPES : BEGIN OF ty_s_col_width,
          width TYPE i,
        END OF ty_s_col_width.

TYPES: ty_it_col_width TYPE STANDARD TABLE OF ty_s_col_width WITH DEFAULT KEY.

* Spaltenbreiten für Tabellenausgabe
DATA(it_col_width) = VALUE ty_it_col_width(
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                            ( width = 30 )
                                          ).

* Mit Hilfe der Klasse cl_fdt_xl_spreadsheet können über XML-Transformationen
* aus XLSX-Dateien Daten extrahiert und in eine interne Tabelle konvertiert werden
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.

* Bild 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 ).

* Excel (itab) -> XML -> Ref-Objekt
* Achtung: Speicherintensiv und rel. langsam! Es sollten keine großen Datenmengen verarbeitet werden.
        DATA(o_excel) = NEW cl_fdt_xl_spreadsheet( document_name = CONV #( it_files[ 1 ]-filename )
                                                   xdocument     = lv_bin_data ).

        DATA: it_worksheet_names TYPE if_fdt_doc_spreadsheet=>t_worksheet_names.

* Worksheetnamen ermitteln
        o_excel->if_fdt_doc_spreadsheet~get_worksheet_names( IMPORTING worksheet_names = it_worksheet_names ).

        IF lines( it_worksheet_names ) > 0.
* erste Worksheet holen und -> REF to itab erstellen
          DATA(o_worksheet_itab) = o_excel->if_fdt_doc_spreadsheet~get_itab_from_worksheet( it_worksheet_names[ 1 ] ).

* Referenz auf generisches Feldsymbol mappen
          FIELD-SYMBOLS: <worksheet> TYPE ANY TABLE.
          ASSIGN o_worksheet_itab->* TO <worksheet>.

* 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 <worksheet>.
          ASSIGN o_row->* TO FIELD-SYMBOL(<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 ).

* Worksheet durchloopen
          LOOP AT <worksheet> 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 = it_col_width[ sy-index ]-width }|.
              ENDIF.
            ENDDO.

            NEW-LINE.
          ENDLOOP.
        ENDIF.
      ENDIF.
    ENDIF.

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

Variante 3 (generische Ausgabe im SALV-Grid)

* Mit Hilfe der Klasse cl_fdt_xl_spreadsheet können über XML-Transformationen
* aus XLSX-Dateien Daten extrahiert und in eine interne Tabelle konvertiert werden
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.

* Bild 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 ).

* Excel (itab) -> XML -> Ref-Objekt
* Achtung: Speicherintensiv und rel. langsam! Es sollten keine großen Datenmengen verarbeitet werden.
        DATA(o_excel) = NEW cl_fdt_xl_spreadsheet( document_name = CONV #( it_files[ 1 ]-filename )
                                                   xdocument     = lv_bin_data ).

        DATA: it_worksheet_names TYPE if_fdt_doc_spreadsheet=>t_worksheet_names.

* Worksheetnamen ermitteln
        o_excel->if_fdt_doc_spreadsheet~get_worksheet_names( IMPORTING worksheet_names = it_worksheet_names ).

        IF lines( it_worksheet_names ) > 0.
* erste Worksheet holen und -> REF to itab erstellen
          DATA(o_worksheet_itab) = o_excel->if_fdt_doc_spreadsheet~get_itab_for_alv_update( ).

* Referenz auf generisches Feldsymbol mappen
          ASSIGN o_worksheet_itab->* TO FIELD-SYMBOL(<worksheet>).

          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        = <worksheet> ).

* 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( 'Worksheet' ).
              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
              LOOP AT o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
                DATA(o_col) = <c>-r_column.
                o_col->set_short_text( || ).
                o_col->set_medium_text( || ).
                o_col->set_long_text( |{ o_col->get_columnname( ) }| ).
              ENDLOOP.

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

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

[ABAP] Excel-Daten in interne Tabelle einlesen

* alternative Funktionsbausteine:
* ALSM_EXCEL_TO_INTERNAL_TABLE -> nur Zellen mit 32 Zeichen Länge
* KCD_EXCEL_OLE_TO_INT_CONVERT -> nur Zellen mit 50 Zeichen Länge
* UPLOAD_XLS_FILE_2_ITAB
* FILE_READ_AND_CONVERT_SAP_DATA
* IMPORT_FROM_SPREADSHEET

TYPES: BEGIN OF ty_data,
         name    TYPE char255,
         gewicht TYPE f,
       END OF ty_data.

DATA: it_raw TYPE truxs_t_text_data.

PARAMETERS: p_file TYPE file_table-filename OBLIGATORY.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
  DATA: lv_rc TYPE i.
  DATA: it_files TYPE filetable.
  DATA: lv_action TYPE i.

* File-Tabelle leeren, da hier noch alte Einträge von vorherigen Aufrufen drin stehen können
  CLEAR it_files.

* FileOpen-Dialog aufrufen
  TRY.
      cl_gui_frontend_services=>file_open_dialog( EXPORTING
                                                    file_filter = |TXT (*.txt)\|*.txt\|XLS (*.xls)\|*.xls\|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
          p_file = it_files[ 1 ]-filename.
        ENDIF.
      ENDIF.

    CATCH cx_root INTO DATA(e_text).
      MESSAGE e_text->get_text( ) TYPE 'I'.
  ENDTRY.

START-OF-SELECTION.

  DATA: it_datatab TYPE STANDARD TABLE OF ty_data.

* Import von Excel-Daten in interne Tabelle über die Ole-Schnittstelle
* Format der Tabelle ist in ty_data definiert
* Unterstützte Dateiformate: *.csv (*.txt), *.xls, *.xlsx
* Das Format der Fließkommazahlen bei CSV muß dem Gebietsschema
* von Excel entsprechen: 1,23 (Dezimalseparator = ',')
  CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP'
    EXPORTING
      i_field_seperator    = ';'                            " Trennzeichen für CSV-Datei
      i_line_header        = abap_true                      " Überschrift in der Tabelle
      i_tab_raw_data       = it_raw
      i_filename           = CONV rlgrap-filename( p_file ) " i_filename -> nur 128 Zeichen für Dateinamenlänge erlaubt
    TABLES
      i_tab_converted_data = it_datatab
    EXCEPTIONS
      conversion_failed    = 1
      OTHERS               = 2.

  IF sy-subrc = 0.
    LOOP AT it_datatab ASSIGNING FIELD-SYMBOL(<fs_line>).
      WRITE: / <fs_line>-name, <fs_line>-gewicht.
    ENDLOOP.
  ELSE.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

Weiterführende Infos: Link