ajanzen.com Excel-Upload
ajanzen.com 1 Einleitung Wie bereits dem Titel zu entnehmen ist, wird in dem vorliegenden Dokument auf den Upload einer Excel-Datei eingegangen. Dabei liegt der Fokus neben dem eigentlichen Upload auf der Logik zur Datenübernahme und Datenkonvertierung vom externen in das interne SAP-Format. Aus dem Beispiel sollte ersichtlich sein, wie das Konzept des Feldsymbols im Rahmen der SPLIT-Anweisung zum Einsatz kommt. Der Einfachheit halber enthält die Excel-Datei Daten aus der SAP-Tabelle SPFLI, sodass eine gewisse Datenstruktur vorausgesetzt ist. Das komplette Beispielcoding ist in Kapitel 3 enthalten. Nähere Informationen zum Ablauf können Kapitel 2 entnommen werden. 1
ajanzen.com 2 Informationen zur Programmlogik Der Selektionsbildschirm ist einfach aufgebaut und bietet die Möglichkeit den Dateipfad einzugeben. Zur erleichterten Pfadauswahl kommt eine F4-Wertehilfe zum Einsatz. Die Verknüpfung vom Pfadparameter und der Verarbeitungsroutine zur F4- Wertehilfe erfolgt über die Anweisung AT SELECTION-SCREEN ON VALUE- REQUEST FOR Parameter. Abbildung 1: Selektionsbildschirm mit der Möglichkeit einer Pfadangabe Die graphisch unterstützte Pfadselektion findet über Methode FILE_OPEN_DIALOG der Klasse CL_GUI_FRONTEND_SERVICES statt. Abbildung 2: Graphisch unterstützte Pfadselektion Zum eigentlichen Excel-Upload kommen OLE2-Objekte zum Einsatz. Diese ermöglichen den direkten Zugriff auf Excel-Funktionen. Abbildung 3 können die wichtigsten angesprochenen Excel-Bestandteile entnommen werden. Für den Datentransfer von Excel ins SAP kommt der Zwischenspeicher zum Einsatz. 2
ajanzen.com Abbildung 3: Übersicht über Excel-OLE2-Objekte Das Ergebnis des Uploads ist eine interne STRING-Tabelle. Den Inhalt dieser Tabelle gilt es im nächsten Schritt vom externen in das SAP-interne Format zu konvertieren und in die entsprechenden Felder zu übernehmen. Zum Trennen der als Zeichenkette vorliegenden und per Raute separierten Informationen, kommt die SPLIT-Anweisung zum Einsatz. Häufig stößt man in Zusammenhang mit der SPLIT-Anweisung auf folgendes Vorgehen (GS_SPFLI ist vom Typ der Struktur SPFLI): Abbildung 4: SPLIT-Anweisung ohne Möglichkeit der Datenkonvertierung 3
ajanzen.com Abgesehen davon, dass die SPLIT-Anweisung aus Abbildung 4 nicht funktioniert, da beispielswiese das Feld PERIOD nicht zeichenartig ist, bietet sie auch folgende Nachteile: Keine Konvertierung von externem in internes Format möglich Programmanpassung bei Strukturerweiterung notwendig Unübersichtlich, wenn die Struktur viele Felder enthält Eine aus meiner Sicht etwas elegantere Möglichkeit ist das Arbeiten mit Feldsymbolen. In dem vorliegenden Beispiel (siehe Kapitel 3) wird in einer DO-Schleife jedes Feld der Ziel-Struktur einzeln angesprochen. Für diese Aktivität kommt die Anweisung ASSIGN COMPONENT Number OF STRUCTURE Structure TO Field_symbol zum Einsatz. Number ist in dabei der Schleifenindex der DO-Schleife (Schleifendurchlauf). Vor dem Durchlaufen der Konvertierungsregeln sind die Eigenschaften des Zielfeldes zu bestimmen. Hierfür bietet SAP die Klasse CL_ABAP_TYPEDESCR. In unserem Fall erfolgt der Aufruf von Methode DESCRIBE_BY_DATA. Das Ergebnis des Methodenaufrufes ist eine Instanz der Klasse CL_ABAP_ELEMDESCR (Casting notwendig). Zum Bestimmen der Feldeigenschaften stellt CL_ABAP_ELEMDESCR wiederum Methode GET_DDIC_FIELD bereit. Anhand der Informationen des Returning-Parameters von GET_DDIC_FIELD wird entweder ein Standard- Konvertierungsexit durchlaufen oder eine Typabhängige manuelle Konvertierung vorgenommen. Abschließend erfolgt unter Verwendung von Klasse CL_SALV_TABLE eine Visualisierung der hochgeladenen Daten. 4
3 Coding *--------------------------------------------------------------------* * Das vorliegende Programm dient der Demonstration eines Excel-Uploads * inklusive der Anwendung von Konvertierungsregeln * * Funktioniert für XLSX... voraussichtlich auch für XLS * * Hinweis: Logik zum eigentlichen Upload stammt zu großen Teilen aus * FuBa KCD_EXCEL_OLE_TO_INT_CONVERT * * Date: 17.03.2015 *--------------------------------------------------------------------* * Änderungen *--------------------------------------------------------------------* REPORT zaj_upload_excel. TYPE-POOLS: soi. * * Globale Datendefinition * CONSTANTS: gc_num TYPE inttype VALUE 'N'. CONSTANTS: gc_dec TYPE inttype VALUE 'P'. CONSTANTS: gc_dat TYPE inttype VALUE 'D'. CONSTANTS: gc_tim TYPE inttype VALUE 'T'. CONSTANTS: gc_comp_num TYPE char20 VALUE ' 0123456789'. CONSTANTS: gc_comp_dec TYPE char20 VALUE ' 0123456789,.- '. DATA: gs_application TYPE ole2_object. DATA: gs_workbook TYPE ole2_object. DATA: gs_range TYPE ole2_object. DATA: gs_worksheet TYPE ole2_object. DATA: gs_cell_first TYPE ole2_object. DATA: gs_cell_last TYPE ole2_object. DATA: gt_file_table TYPE filetable. DATA: gv_rc TYPE i. DATA: gv_file TYPE file_table. DATA: gt_imp_tab_strg TYPE STANDARD TABLE OF string. DATA: gv_string TYPE string. DATA: gt_spfli TYPE STANDARD TABLE OF spfli. DATA: gs_spfli TYPE spfli.
DATA: gr_salv DATA: gr_columns DATA: gr_err_salv DATA: gv_split_char DATA: gr_element_descr DATA: gs_dfies FIELD-SYMBOLS: <gv_field> TYPE REF TO cl_salv_table. TYPE REF TO cl_salv_columns_table. TYPE REF TO cx_salv_msg. TYPE char100. TYPE REF TO cl_abap_elemdescr. TYPE dfies. TYPE any. * Selektionsbildschirm PARAMETERS: p_file TYPE string OBLIGATORY. * F4-Wertehilfe zur Datenauswahl AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file. CALL METHOD cl_gui_frontend_services=>file_open_dialog window_title = 'Auswahl einer EXCEL-Datei' CHANGING file_table = gt_file_table rc = gv_rc EXCEPTIONS file_open_dialog_failed = 1 cntl_error = 2 error_no_gui = 3 not_supported_by_gui = 4 OTHERS = 5. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
* ausgewählte Datei bestimmen READ TABLE gt_file_table INTO gv_file INDEX 1. MOVE gv_file TO p_file. * Eigentliche Verarbeitung START-OF-SELECTION. * Excel-Applikation starten und im Vorfeld selektiertes Dokument öffnen CREATE OBJECT gs_application 'Excel.Application'. gs_application 'Workbooks' = gs_workbook. gs_workbook 'Open' #1 = p_file. GET PROPERTY OF gs_application 'ACTIVESHEET' = gs_worksheet. * Relevanten Bereich festlegen... gs_worksheet 'Cells' = gs_cell_first #1 = 1 "Ab der ersten Zeile #2 = 1. " Ab der ersten Spalte gs_worksheet 'Cells' = gs_cell_last #1 = 99999 " Bis zu 99.999 Zeilen
#2 = 1000. "Bis zu 1.000 Spalten gs_worksheet 'RANGE' = gs_range #1 = gs_cell_first #2 = gs_cell_last. *... und selektieren gs_range 'SELECT'. * Selektierte Daten in die Zwischenablage kopieren gs_range 'COPY'. CALL FUNCTION 'CONTROL_FLUSH' EXCEPTIONS OTHERS = 3. IF sy-subrc NE 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. * Daten aus der zwischenablage in interne Tabelle übernehmen CALL FUNCTION 'CLPB_IMPORT' TABLES data_tab = gt_imp_tab_strg EXCEPTIONS clpb_error = 1 OTHERS = 2. IF sy-subrc NE 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. * Excel-Applikation wieder beenden SET PROPERTY OF gs_application 'CutCopyMode' = 0. gs_application 'QUIT'. FREE OBJECT gs_application. * Informationen aus der string-tabelle in importstruktur übernehmen LOOP AT gt_imp_tab_strg INTO gv_string. CLEAR: gs_spfli. ** Datesplit durchführen DO. ASSIGN COMPONENT sy-index OF STRUCTURE gs_spfli TO <gv_field>. * IF sy-subrc NE 0. * Keine Felder mehr... die DO-Schleife verlassen EXIT. * Die nächste zu übertragende Zelle bestimmen SPLIT gv_string AT cl_abap_char_utilities=>horizontal_tab INTO gv_split_char gv_string. ). gr_element_descr?= cl_abap_typedescr=>describe_by_data( <gv_field> gs_dfies = gr_element_descr->get_ddic_field( ).
* Konvertierungsregeln anwenden IF gs_dfies-convexit IS NOT INITIAL. * Wenn Konvertierungsroutine hinterlegt ist, diese durchlaufen CALL FUNCTION 'UPF_INPUT_CONVERT' i_convexit = gs_dfies-convexit i_outputlen = gs_dfies-outputlen i_intlen = gs_dfies-leng "intlen i_input_value = gv_split_char IMPORTING e_converted_value = gv_split_char EXCEPTIONS input_is_not_numeric = 1 date_does_not_exist = 2 date_format_unrecognized = 3 conversion_failure = 4 OTHERS = 5. IF sy-subrc EQ 0. MOVE gv_split_char TO <gv_field>. ELSE. * Sonst die Konnvertierung in Abhängigkeit vom Datentyp durchlaufen CASE gs_dfies-inttype. WHEN gc_num. ** numerische Werte ** IF gv_split_char CO gc_comp_num. MOVE gv_split_char TO <gv_field>. WHEN gc_dec. ** Dezimalwerte ** IF gv_split_char CO gc_comp_dec. CALL FUNCTION 'CONVERSION_EXIT_FLOAT_INPUT'
input = gv_split_char IMPORTING output = <gv_field>. WHEN gc_dat. ** Datum konvertieren ** CALL FUNCTION 'CONVERT_DATE_TO_INTERNAL' date_external = gv_split_char accept_initial_date = abap_true IMPORTING date_internal = <gv_field> EXCEPTIONS date_external_is_invalid = 1 OTHERS = 2. IF sy-subrc <> 0. * Kein Fehler... in diesem Fall findet keine Übernahme statt CLEAR: <gv_field>. WHEN gc_tim. ** Zeit konvertieren ** CALL FUNCTION 'CONVERT_TIME_INPUT' input = gv_split_char IMPORTING output = <gv_field> EXCEPTIONS plausibility_check_failed = 1 wrong_format_in_input = 2 OTHERS = 3. IF sy-subrc <> 0. * Kein Fehler... in diesem Fall findet keine Übernahme statt CLEAR: <gv_field>.
WHEN OTHERS. ** Sonst Datenübernahme one Konvertierung ** MOVE gv_split_char TO <gv_field>. ENDCASE. * Konvertierung abgeschlossen IF gv_string IS INITIAL. * fertig mit dem SPLIT... und die DO-Schleife verlassen EXIT. ENDDO. * Informationsübernahme abgeschlossen ** Datensat für die Folgeverarbeitung übernehmen APPEND gs_spfli TO gt_spfli. ENDLOOP. * Daten anzeigen TRY. CALL METHOD cl_salv_table=>factory list_display = if_salv_c_bool_sap=>false IMPORTING r_salv_table = gr_salv
CHANGING t_table = gt_spfli. CATCH cx_salv_msg INTO gr_err_salv. * Fehler anzeigen gv_string = gr_err_salv->get_text( ). MESSAGE gv_string TYPE 'E'. ENDTRY. * Spaltenbreite optimieren gr_columns = gr_salv->get_columns( ). gr_columns->set_optimize( abap_true ). " nur ein 'X' * Die eigentliche Anzeige gr_salv->display( ).