ajanzen.com
CSV-Upload
ajanzen.com
1
1 Einleitung
Wie bereits dem Titel zu entnehmen ist, wird in dem vorliegenden Dokument auf den
Upload einer CSV-Datei eingegangen. Dabei liegt der Fokus nicht auf dem
eigentlichen Upload sondern 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.
Hinweis: In diesem Beispiel wird davon ausgegangen, dass die einzelnen Felder einer
Zeile über Semikolon voneinander getrennt sind.
Der Einfachheit halber enthält die CSV-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.
ajanzen.com
2
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öglichke it 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 CSV-Upload greife ich auf Methode GUI_UPLOAD der Klasse
CL_GUI_FRONTEND_SERVICES zurück.
Hinweis: Diese Klasse bildet eine Funktionssammlung, löst teilweise die „alten“
Funktionsbausteine ab und enthält viele nützliche Methoden.
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
ajanzen.com
3
und in die entsprechenden Felder zu übernehmen. Zum Trennen der als Zeichenkette
vorliegenden und per Semikolon 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 3: SPLIT-Anweisung ohne Möglichkeit der D atenkonvertierung
Abgesehen davon, dass die SPLIT-Anweisung aus Abbildung 3 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
ajanzen.com
4
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.
3 Coding
*-------------------------------------------------- ------------------*
* Das vorliegende Programm dient der Demonstration eines CSV-Uploads
* inklusive der Anwendung von Konvertierungsregeln
*
* Date: 24.02.2014
*-------------------------------------------------- ------------------*
* Änderungen
*-------------------------------------------------- ------------------*
REPORT zaj_upload_csv .
*************************************************** **********************
* 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_semikolon TYPE char1 VALUE ';' .
CONSTANTS: gc_comp_num TYPE char20 VALUE ' 0123456789' .
CONSTANTS: gc_comp_dec TYPE char20 VALUE ' 0123456789,.- ' .
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 TYPE REF TO cl_salv_table .
DATA: gr_columns TYPE REF TO cl_salv_columns_table .
DATA: gr_err_salv TYPE REF TO cx_salv_msg .
DATA: gv_split_char TYPE char100 .
DATA: gr_element_descr TYPE REF TO cl_abap_elemdescr .
DATA: gs_dfies TYPE dfies .
FIELD-SYMBOLS: <gv_field> 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
EXPORTING
window_title = 'Auswahl CSV-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.
ENDIF.
* 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.
*************************************************** ************************
****
* Upload der Datei
*************************************************** ************************
****
cl_gui_frontend_services =>gui_upload (
EXPORTING
filename = p_file
CHANGING
data_tab = gt_imp_tab_strg
EXCEPTIONS
OTHERS = 1
).
IF sy - subrc <> 0.
MESSAGE ID sy - msgid TYPE sy - msgty NUMBER sy - msgno
WITH sy - msgv1 sy - msgv2 sy - msgv3 sy - msgv4.
ENDIF.
*************************************************** ************************
****
* Informationen aus der string-tabelle in importst ruktur ü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 .
ENDIF.
* Die nächste zu übertragende Zelle bestimmen
SPLIT gv_string AT gc_semikolon 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, d iese durchlaufen
CALL FUNCTION 'UPF_INPUT_CONVERT'
EXPORTING
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> .
ENDIF.
ELSE.
* Sonst die Konnvertierung in Abhängigkeit vo m 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> .
ENDIF.
WHEN gc_dec .
********** Dezimalwerte ******************
IF gv_split_char CO gc_comp_dec .
CALL FUNCTION 'CONVERSION_EXIT_FLOAT_INPUT'
EXPORTING
input = gv_split_char
IMPORTING
output = <gv_field> .
ENDIF.
WHEN gc_dat .
********** Datum konvertieren ******************
CALL FUNCTION 'CONVERT_DATE_TO_INTERNAL'
EXPORTING
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 fin det keine Übernahme
statt
CLEAR: <gv_field> .
ENDIF.
WHEN gc_tim .
********** Zeit konvertieren ******************
CALL FUNCTION 'CONVERT_TIME_INPUT'
EXPORTING
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 fin det keine Übernahme
statt
CLEAR: <gv_field> .
ENDIF.
WHEN OTHERS.
********** Sonst Datenübernahme one Konvertierung ******************
MOVE gv_split_char TO <gv_field> .
ENDCASE.
ENDIF.
*************************************************** ************************
****
* Konvertierung abgeschlossen
*************************************************** ************************
****
IF gv_string IS INITIAL .
* fertig mit dem SPLIT ... und die DO-Schleife verl assen
EXIT .
ENDIF.
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
EXPORTING
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 ( ).