Загрузка многостраничного Excel без ограничений по длине значения.

Как-то раз на проекте возникла задача.

Необходимо было читать данные с нескольких страниц 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.