Автор Тема: Чтение данных из EXCEL (ALSM_EXCEL_TO_INTERNAL_TABLE)  (Прочитано 15271 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Uukrul

  • SAP ECC 6.0 Ehp(*)
  • Administrator
  • Epic Member
  • *****
  • Сообщений: 3 761
  • Репутация: +47/-0
  • Пол: Мужской
  • YearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYears
    • Sapforum.BIZ
Чтение данных из EXCEL (ALSM_EXCEL_TO_INTERNAL_TABLE)
« : Январь 28, 2013, 03:54:44 pm »
ALSM_EXCEL_TO_INTERNAL_TABLE - Стандартный модуль системы SAP который позволяет прочитать данные из файла таблицы Excel во внутреннюю таблицу программы. Работает только на системах WINxx так как в других системах MS Office пока не сильно прижился вместе со своим API. На входе запрашивается файл и начальная и конечная ячейки активного листа. Данные загружаются во внутреннюю таблицу типа ALSMEX_TABLINE.
Код: You are not allowed to view links. Register or Login
DATA: l_filename LIKE rlgrap-filename,
      lt_tabline TYPE alsmex_tabline OCCURS 1 WITH HEADER LINE.

l_filename = 'C:\text.xls'.
CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
  EXPORTING
    filename                = l_filename
    i_begin_col             = 1
    i_begin_row             = 1
    i_end_col               = 10
    i_end_row               = 10
  TABLES
    intern                  = lt_tabline
  EXCEPTIONS
    inconsistent_parameters = 1
    upload_ole              = 2
    OTHERS                  = 3.

IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
Структура прочитанных данных в таблице lt_tabline будет заполнена в следующем виде:
  • ROW - Строка ячейки
  • COL - Колонка ячейки
  • VALUE - Значение в ячейке
Во внутреннюю таблицу попадают только ячейки которые находятся в заданной при вызове функции области и только те, которые содержат какое-либо значение. Пустые ячейки с пустым значением в поле VALUE в результирующей таблице будут отсутствовать.

В общем как бы стандартный модуль есть, но пользоваться им не очень удобно, так как на выходе или входе имеем следующие ограничения:
  • Нужно знать размеры области, значения из которой хотим прочитать
  • Читается всегда область с активного листа, т.е. то лист который при сохранении файла был видимым/активным
  • Значение в ячейке ограничивается по длине в 20 символов, так как элемент данных VALUE это CHAR20
В общем как обычно, функция есть, но чтобы ей воспользоватся...  надо сильно устать.

PS: Чуть позже выложу улучшенный вариант для этой кухни, которым можно уже нормально пользоватся

Оффлайн DEAD_MOROZ

  • Newbie
  • *
  • Сообщений: 63
  • Репутация: +0/-0
  • YearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYears
Re: Чтение данных из EXCEL (ALSM_EXCEL_TO_INTERNAL_TABLE)
« Ответ #1 : Январь 29, 2013, 08:29:17 am »
- Значение в ячейке ограничивается по длине в 20 символов, так как элемент данных VALUE это CHAR20
Небольшая неточность:
Тип данных  поля VALUE  - CHAR50

Оффлайн Uukrul

  • SAP ECC 6.0 Ehp(*)
  • Administrator
  • Epic Member
  • *****
  • Сообщений: 3 761
  • Репутация: +47/-0
  • Пол: Мужской
  • YearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYears
    • Sapforum.BIZ
Re: Чтение данных из EXCEL (ALSM_EXCEL_TO_INTERNAL_TABLE)
« Ответ #2 : Январь 29, 2013, 03:16:02 pm »
В общем для упрощения работы и расширения функциональности были разработаны два модуля для чтения данных из EXCEL (на основании ALSM_EXCEL_TO_INTERNAL_TABLE) и второй модуль который производит заполнение внутренней таблицы переданной в качестве параметра, при этом если в таблице EXCEL есть имена колонок (строка заголовка), то данные раскладываются по соответствующим полям внутренней таблицы.

Функциональный модуль: Y_ALSM_EXCEL_TO_INTERNAL_TABLE - Чтение данных из EXCEL таблицы с заданного листа/активного листа. Читается или все данные листа или только данные из выбранной области. Структура YTSH_ALSMEX_TABLINE, аналогична структуре ALSMEX_TABLINE, только переменная VALUE расширена до 255 символов, тут как говорится по желанию.
Код: You are not allowed to view links. Register or Login
FUNCTION y_alsm_excel_to_internal_table .
*"----------------------------------------------------------------------
*"*"Локальный интерфейс:
*"  IMPORTING
*"     VALUE(FILENAME) LIKE  RLGRAP-FILENAME
*"     VALUE(SHEET_NAME) TYPE  CHAR30 OPTIONAL
*"     VALUE(I_BEGIN_COL) TYPE  I OPTIONAL
*"     VALUE(I_BEGIN_ROW) TYPE  I OPTIONAL
*"     VALUE(I_END_COL) TYPE  I OPTIONAL
*"     VALUE(I_END_ROW) TYPE  I OPTIONAL
*"  TABLES
*"      INTERN STRUCTURE  YTSH_ALSMEX_TABLINE
*"  EXCEPTIONS
*"      INCONSISTENT_PARAMETERS
*"      ERROR_OLE
*"----------------------------------------------------------------------

  DATA: excel_tab      TYPE  ty_t_sender.
  DATA: ld_separator   TYPE  c.
  DATA: application    TYPE  ole2_object,
        workbook       TYPE  ole2_object,
        range          TYPE  ole2_object,
        worksheet      TYPE  ole2_object,
        activeworkbook TYPE  ole2_object.
  DATA: h_cell_start   TYPE  ole2_object,
        h_cell_end     TYPE  ole2_object.
  DATA:
    ld_rc             TYPE i.
*   Rückgabewert der Methode "clipboard_export     "

* Makro für Fehlerbehandlung der Methods
  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. raise error_ole.
    endcase.
  END-OF-DEFINITION.


* check parameters
  IF i_begin_row > i_end_row. RAISE inconsistent_parameters. ENDIF.
  IF i_begin_col > i_end_col. RAISE inconsistent_parameters. ENDIF.

* Get TAB-sign for separation of fields
  CLASS cl_abap_char_utilities DEFINITION LOAD.
  ld_separator = cl_abap_char_utilities=>horizontal_tab.

* open file in Excel
  IF application-header = space OR application-handle = -1.
    CREATE OBJECT application 'Excel.Application'.
    m_message.
  ENDIF.
  SET PROPERTY OF application 'DisplayAlerts' = 0.
  m_message.

  CALL METHOD OF application 'Workbooks' = workbook.
  m_message.

  CALL METHOD OF workbook 'Open' EXPORTING #1 = filename.
  m_message.

  IF sheet_name = space.
    GET PROPERTY OF application 'ACTIVESHEET' = worksheet.
    m_message.
  ELSE.
    CALL METHOD OF application 'ActiveWorkbook' = activeworkbook.
    m_message.
    CALL METHOD OF activeworkbook 'WorkSheets' = worksheet
      EXPORTING #1 = sheet_name.
    m_message.
    CALL METHOD OF worksheet 'Select'.
    m_message.
  ENDIF.

  IF ( i_begin_row = space OR i_begin_col = space ) AND
     ( i_end_row = space OR i_end_col = space ).
    CALL METHOD OF worksheet 'Columns' = h_cell_start.
    m_message.
    CALL METHOD OF worksheet 'Rows' = h_cell_end.
    m_message.
  ELSE.
*   mark whole spread sheet
    CALL METHOD OF worksheet 'Cells' = h_cell_start
      EXPORTING #1 = i_begin_row #2 = i_begin_col.
    m_message.
    CALL METHOD OF worksheet 'Cells' = h_cell_end
      EXPORTING #1 = i_end_row #2 = i_end_col.
    m_message.
  ENDIF.

  CALL METHOD OF worksheet 'RANGE' = range
    EXPORTING #1 = h_cell_start #2 = h_cell_end.
  m_message.

  CALL METHOD OF range 'SELECT'.
  m_message.

* copy marked area (whole spread sheet) into Clippboard
  CALL METHOD OF range 'COPY'.
  m_message.

* read clipboard into ABAP
  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
          .
  IF sy-subrc <> 0. MESSAGE a037(alsmex). ENDIF.

  PERFORM separated_to_intern_convert TABLES excel_tab 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.
  IF sy-subrc <> 0. MESSAGE a037(alsmex). ENDIF.

* quit Excel and free ABAP Object - unfortunately, this does not kill
* the Excel process
  CALL METHOD OF application 'QUIT'.
  m_message.

* to kill the Excel process it's necessary to free all used objects
  FREE OBJECT h_cell_start.   m_message.
  FREE OBJECT h_cell_end.     m_message.
  FREE OBJECT range.          m_message.
  FREE OBJECT worksheet.      m_message.
  FREE OBJECT workbook.       m_message.
  FREE OBJECT activeworkbook. m_message.
  FREE OBJECT application.    m_message.
ENDFUNCTION.
Используемые подпрограммы INCLUDE LYTSH_ALSMEXF01
Код: You are not allowed to view links. Register or Login
*----------------------------------------------------------------------*
***INCLUDE LYTSH_ALSMEXF01 .
*----------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*&      Form  SEPARATED_TO_INTERN_CONVERT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
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.                    "line_to_cell_separat

*---------------------------------------------------------------------*
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.                    "line_to_cell_esc_sep
Данные TOP-иклуда:
Код: You are not allowed to view links. Register or Login
FUNCTION-POOL ytsh_alsmex.                  "MESSAGE-ID ..

TYPE-POOLS: ole2.

*      value of excel-cell
TYPES: ty_d_itabvalue             TYPE ytsh_alsmex_tabline-value,
*      internal table containing the excel data
       ty_t_itab                  TYPE ytsh_alsmex_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.

*
CONSTANTS:  gc_esc              VALUE '"'.


Далее для упрощения чтения данных во внутренние таблицы используется функциональный модуль: Y_TSH_EXCEL_LOAD_TO_INTTABLE. Данные модуль вызывает Y_ALSM_EXCEL_TO_INTERNAL_TABLE а затем полученные данные из ячеек таблицы EXCEL размешает в поля полученной на входе внутренней таблицы.
Код: You are not allowed to view links. Register or Login
FUNCTION y_tsh_excel_load_to_inttable .
*"----------------------------------------------------------------------
*"*"Локальный интерфейс:
*"  IMPORTING
*"     REFERENCE(FILENAME) LIKE  RLGRAP-FILENAME
*"     REFERENCE(SHEET_NAME) TYPE  CHAR30 OPTIONAL
*"     REFERENCE(HEADER_ROW) TYPE  SY-TABIX DEFAULT 1
*"  TABLES
*"      IT_DATA
*"  EXCEPTIONS
*"      ERROR
*"      HEADER_LINE_NOT_SET
*"----------------------------------------------------------------------
  DATA: ls_intern LIKE ytsh_alsmex_tabline,
        lt_intern LIKE ytsh_alsmex_tabline OCCURS 1 WITH HEADER LINE.
  DATA: l_fld_name(50) TYPE c,
        l_type(1)      TYPE c.
  FIELD-SYMBOLS: <fld> TYPE ANY.


  IF header_row = space. RAISE header_line_not_set. ENDIF.

  CALL FUNCTION 'Y_ALSM_EXCEL_TO_INTERNAL_TABLE'
    EXPORTING
      filename                = filename
      sheet_name              = sheet_name
    TABLES
      intern                  = lt_intern
    EXCEPTIONS
      inconsistent_parameters = 1
      error_ole               = 2
      OTHERS                  = 3.
  IF sy-subrc <> 0. RAISE error. ENDIF.

  REFRESH: it_data.
  LOOP AT lt_intern WHERE row <> header_row.
    ON CHANGE OF lt_intern-row.
      IF it_data <> space. APPEND it_data. ENDIF.
      CLEAR: it_data.
    ENDON.
    READ TABLE lt_intern INTO ls_intern
                         WITH KEY row = header_row col = lt_intern-col.
    CONCATENATE 'IT_DATA-' ls_intern-value INTO l_fld_name.
    ASSIGN (l_fld_name) TO <fld>.
    IF sy-subrc = 0.
      DESCRIBE FIELD <fld> TYPE l_type.
      CASE l_type.
        WHEN 'F' OR 'P'. REPLACE ',' WITH '.' INTO lt_intern-value.
      ENDCASE.
      <fld> = lt_intern-value.
      UNASSIGN <fld>.
    ENDIF.
  ENDLOOP.
  IF sy-subrc = 0. APPEND it_data. ENDIF.
ENDFUNCTION.
Предполагается, что в переменной HEADER_ROW задается строка EXCEL-таблицы, которая содержит имена колонок внутренней таблицы.

PS: По быстрому типа хватает в большинстве случаев.
PS: 30.02.2013 Подправил работу с типами переменных, чтобы при при запятой в поле числа, была замена на точку, если значение ячейки копируется в переменную типа FLOAT.
« Последнее редактирование: Январь 30, 2013, 03:50:56 pm от Uukrul »

Оффлайн NachDenken

  • Newbie
  • *
  • Сообщений: 158
  • Репутация: +9/-0
  • YearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYears
Re: Чтение данных из EXCEL (ALSM_EXCEL_TO_INTERNAL_TABLE)
« Ответ #3 : Февраль 01, 2013, 10:57:16 pm »
30.02.2013 это сила!

Оффлайн Uukrul

  • SAP ECC 6.0 Ehp(*)
  • Administrator
  • Epic Member
  • *****
  • Сообщений: 3 761
  • Репутация: +47/-0
  • Пол: Мужской
  • YearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYearsYears
    • Sapforum.BIZ
Re: Чтение данных из EXCEL (ALSM_EXCEL_TO_INTERNAL_TABLE)
« Ответ #4 : Февраль 04, 2013, 11:43:16 am »
You are not allowed to view links. Register or Login
30.02.2013 это сила!
Ну не 32 мая же... как предлагал барон Мюнхаузен.. я более гуманно решил  8)