Как-то раз на проекте возникла задача.
Необходимо было читать данные с нескольких страниц Excel в SAP, чтобы потом использовать эти данные.
Причем необходимо было обойти стандартное ограничение загрузки из Excel в 50 символов на значение.
Реализовано это следующим образом.
В словаре необходимо создать структуры:
ZBC_S_EXCEL_SHEETS_DATA
|
SHEET_NAME |
1 |
Тип |
TEXT100 |
|
SHEET_DATA |
3 |
Тип ссыл. На |
DATA |
и
ZALSMEX_TABLINE
|
ROW |
1 |
Тип |
KCD_EX_ROW_N |
|
COL |
1 |
Тип |
KCD_EX_COL_N |
|
VALUE |
1 |
Тип |
STRING |
Тип таблицы
ZBC_TT_EXCEL_SHEETS_DATA —> ZBC_S_EXCEL_SHEETS_DATA
Вызов ФМ загрузчика многостраничного Excel:
DATA gt_excel_sheets_data TYPE zbc_tt_excel_sheets_data.
DATA lv_filename TYPE string.
CALL FUNCTION 'ZBC_EXCEL_MULTISHEET_UPLPOAD'
EXPORTING
iv_filename = lv_filename
IMPORTING
et_excel_sheets_data = gt_excel_sheets_data.
Исходный код ФМ ZBC_EXCEL_MULTISHEET_UPLPOAD:
FUNCTION zbc_excel_multisheet_uplpoad.
*"----------------------------------------------------------------------
*"*"Локальный интерфейс:
*" IMPORTING
*" REFERENCE(IV_FILENAME) TYPE STRING
*" EXPORTING
*" REFERENCE(ET_EXCEL_SHEETS_DATA) TYPE ZBC_TT_EXCEL_SHEETS_DATA
*"----------------------------------------------------------------------
DATA lt_strs TYPE string_t.
DATA: lo_application TYPE ole2_object,
lo_workbook TYPE ole2_object,
lo_sheet_was TYPE ole2_object,
lo_sheet TYPE ole2_object,
lo_cell_beg TYPE ole2_object,
lo_cell_end TYPE ole2_object,
lo_range TYPE ole2_object.
DATA ls_excel_sheets_data LIKE LINE OF et_excel_sheets_data.
DATA lv_begin_sheet_index TYPE i.
DATA lv_current_sheet_index TYPE i.
DATA lv_current_sheet_index_c(2) TYPE c.
CLEAR lv_begin_sheet_index.
CLEAR lv_current_sheet_index.
CLEAR lv_current_sheet_index_c.
lv_current_sheet_index = 0.
lv_current_sheet_index_c = space.
" Сформировать объект с прилождением
CREATE OBJECT lo_application 'Excel.Application'.
m_message.
" Открыть книгу
CALL METHOD OF lo_application 'Workbooks' = lo_workbook.
m_message.
CALL METHOD OF lo_workbook 'Open'
EXPORTING
#1 = iv_filename.
m_message.
DO.
ADD 1 TO lv_current_sheet_index.
lv_current_sheet_index_c = lv_current_sheet_index.
" Невидимо
SET PROPERTY OF lo_application 'Visible' = 0.
m_message.
" Без сообщений
SET PROPERTY OF lo_application 'DisplayAlerts' = 0.
m_message.
" Без обновлений экрана
SET PROPERTY OF lo_application 'ScreenUpdating' = 0.
m_message.
" Получить индекс первой страницы
IF lv_begin_sheet_index IS INITIAL.
" Запомнить какой лист был открыт изначально
GET PROPERTY OF lo_application 'ACTIVESHEET' = lo_sheet_was.
m_message.
GET PROPERTY OF lo_sheet_was 'INDEX' = lv_begin_sheet_index.
m_message.
ENDIF.
" Выделить следующий по порядку лист
CALL METHOD OF lo_application 'Worksheets' = lo_sheet
EXPORTING
#1 = lv_current_sheet_index.
" Если листов больше нет - закрыть Excel
IF sy-subrc NE 0.
EXIT.
ENDIF.
" Активировать лист по порядку - пока не кончатся листы
CALL METHOD OF lo_sheet 'ACTIVATE'.
m_message.
"Range("A1").Select
"Range(Selection, ActiveCell.SpecialCells(xlLastCell)).Select
" Выделить все данные ан листе
CALL METHOD OF lo_sheet 'Cells' = lo_cell_beg
EXPORTING #1 = 1 #2 = 1.
m_message.
* CALL METHOD OF lo_cell_beg 'SELECT' = lo_selection.
* CALL METHOD OF lo_sheet 'Cells' = lo_cell_end
* EXPORTING #1 = 1 #2 = 1.
* m_message.
CALL METHOD OF lo_cell_beg 'SpecialCells' = lo_cell_end
EXPORTING
#1 = 11. " xlLastCell
CALL METHOD OF lo_sheet 'RANGE' = lo_range
EXPORTING #1 = lo_cell_beg
#2 = lo_cell_end.
m_message.
CALL METHOD OF lo_range 'SELECT'.
m_message.
* copy marked area (whole spread sheet) into Clippboard
CALL METHOD OF lo_range 'COPY'.
m_message.
CALL FUNCTION 'FLUSH'
EXCEPTIONS
cntl_system_error = 1
cntl_error = 2
OTHERS = 3.
DATA: excel_tab TYPE ty_t_sender.
DATA:
ld_rc TYPE i.
DATA: ld_separator TYPE c.
DATA lt_xls_intern TYPE TABLE OF zalsmex_tabline.
* read clipboard into ABAP
DATA lv_counter TYPE i.
lv_counter = 0.
WHILE excel_tab IS INITIAL
AND lv_counter LT 20.
WAIT UP TO 1 SECONDS.
CALL METHOD cl_gui_frontend_services=>clipboard_import
IMPORTING
data = excel_tab
EXCEPTIONS
cntl_error = 1
* ERROR_NO_GUI = 2
* NOT_SUPPORTED_BY_GUI = 3
OTHERS = 4.
ADD 1 TO lv_counter.
ENDWHILE.
IF sy-subrc <> 0.
MESSAGE a037(alsmex).
ENDIF.
* Get TAB-sign for separation of fields
CLASS cl_abap_char_utilities DEFINITION LOAD.
ld_separator = cl_abap_char_utilities=>horizontal_tab.
PERFORM separated_to_intern_convert TABLES excel_tab lt_xls_intern
USING ld_separator.
* clear clipboard
REFRESH excel_tab.
CALL METHOD cl_gui_frontend_services=>clipboard_export
IMPORTING
data = excel_tab
CHANGING
rc = ld_rc
EXCEPTIONS
cntl_error = 1
* ERROR_NO_GUI = 2
* NOT_SUPPORTED_BY_GUI = 3
OTHERS = 4.
* DATA: it_raw_data TYPE truxs_t_text_data,
* lv_filename LIKE rlgrap-filename.
*
* lv_filename = iv_filename.
*
*
* CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
* EXPORTING
* filename = lv_filename
* i_begin_col = 1
* i_begin_row = 1
* i_end_col = 30
* i_end_row = 400
* TABLES
* intern = lt_xls_intern
* EXCEPTIONS
* inconsistent_parameters = 1
* upload_ole = 2
* OTHERS = 3.
ls_excel_sheets_data-sheet_name = lv_current_sheet_index.
CREATE DATA ls_excel_sheets_data-sheet_data LIKE lt_xls_intern.
FIELD-SYMBOLS <ft> TYPE ANY TABLE.
ASSIGN ls_excel_sheets_data-sheet_data->* TO <ft>.
IF sy-subrc EQ 0.
<ft> = lt_xls_intern.
ENDIF.
APPEND ls_excel_sheets_data TO et_excel_sheets_data.
ENDDO.
" Звкрыть приложение
CALL METHOD OF lo_application 'QUIT'.
" Убить процесс
FREE OBJECT:
lo_application ,
lo_workbook ,
lo_sheet_was ,
lo_sheet ,
lo_cell_beg ,
lo_cell_end ,
lo_range .
ENDFUNCTION.
Исходный код TOP Icnlude группы функций для данного ФМ:
INCLUDE LZBC_EXCELD... " Local class definition
TYPE-POOLS: ole2.
* value of excel-cell
TYPES: ty_d_itabvalue TYPE zalsmex_tabline-value,
* internal table containing the excel data
ty_t_itab TYPE zalsmex_tabline OCCURS 0,
* line type of sender table
BEGIN OF ty_s_senderline,
line(4096) TYPE c,
END OF ty_s_senderline,
* sender table
ty_t_sender TYPE ty_s_senderline OCCURS 0.
DEFINE m_message.
case sy-subrc.
when 0.
when 1.
message id sy-msgid type sy-msgty number sy-msgno
with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
when others.
endcase.
END-OF-DEFINITION.
CONSTANTS: gc_esc VALUE '"'.
А также в группе функций должны быть объявлены подпрограммы:
FORM separated_to_intern_convert TABLES i_tab TYPE ty_t_sender
i_intern TYPE ty_t_itab
USING i_separator TYPE c.
DATA: l_sic_tabix LIKE sy-tabix,
l_sic_col TYPE kcd_ex_col.
DATA: l_fdpos LIKE sy-fdpos.
REFRESH i_intern.
LOOP AT i_tab.
l_sic_tabix = sy-tabix.
l_sic_col = 0.
WHILE i_tab CA i_separator.
l_fdpos = sy-fdpos.
l_sic_col = l_sic_col + 1.
PERFORM line_to_cell_separat TABLES i_intern
USING i_tab l_sic_tabix l_sic_col
i_separator l_fdpos.
ENDWHILE.
IF i_tab <> space.
CLEAR i_intern.
i_intern-row = l_sic_tabix.
i_intern-col = l_sic_col + 1.
i_intern-value = i_tab.
APPEND i_intern.
ENDIF.
ENDLOOP.
ENDFORM. " SEPARATED_TO_INTERN_CONVERT
*---------------------------------------------------------------------*
FORM line_to_cell_separat TABLES i_intern TYPE ty_t_itab
USING i_line
i_row LIKE sy-tabix
ch_cell_col TYPE kcd_ex_col
i_separator TYPE c
i_fdpos LIKE sy-fdpos.
DATA: l_string TYPE ty_s_senderline.
DATA l_sic_int TYPE i.
CLEAR i_intern.
l_sic_int = i_fdpos.
i_intern-row = i_row.
l_string = i_line.
i_intern-col = ch_cell_col.
* csv Dateien mit separator in Zelle: --> ;"abc;cd";
IF ( i_separator = ';' OR i_separator = ',' ) AND
l_string(1) = gc_esc.
PERFORM line_to_cell_esc_sep USING l_string
l_sic_int
i_separator
i_intern-value.
ELSE.
IF l_sic_int > 0.
i_intern-value = i_line(l_sic_int).
ENDIF.
ENDIF.
IF l_sic_int > 0.
APPEND i_intern.
ENDIF.
l_sic_int = l_sic_int + 1.
i_line = i_line+l_sic_int.
ENDFORM.
*---------------------------------------------------------------------*
FORM line_to_cell_esc_sep USING i_string
i_sic_int TYPE i
i_separator TYPE c
i_intern_value TYPE ty_d_itabvalue.
DATA: l_int TYPE i,
l_cell_end(2).
FIELD-SYMBOLS: <l_cell>.
l_cell_end = gc_esc.
l_cell_end+1 = i_separator .
IF i_string CS gc_esc.
i_string = i_string+1.
IF i_string CS l_cell_end.
l_int = sy-fdpos.
ASSIGN i_string(l_int) TO <l_cell>.
i_intern_value = <l_cell>.
l_int = l_int + 2.
i_sic_int = l_int.
i_string = i_string+l_int.
ELSEIF i_string CS gc_esc.
* letzte Celle
l_int = sy-fdpos.
ASSIGN i_string(l_int) TO <l_cell>.
i_intern_value = <l_cell>.
l_int = l_int + 1.
i_sic_int = l_int.
i_string = i_string+l_int.
l_int = strlen( i_string ).
IF l_int > 0 . MESSAGE x001(kx) . ENDIF.
ELSE.
MESSAGE x001(kx) . "was ist mit csv-Format
ENDIF.
ENDIF.
ENDFORM.
