사용자가 보내준 Excel 데이터를 SAP에 저장하지 않고 ALV로 바로 보기만 하고 싶을 때 가 있습니다. 데이터 검토·검증·임시 분석 같은 작업이죠. CBO 테이블에 저장하는 별도의 업로드 프로그램을 만들기는 과해 보이고, 그렇다고 SE16N에 직접 붙여넣기도 번거롭습니다.
SAP NetWeaver 7.40 이상에서는 표준 클래스 cl_fdt_xl_spreadsheet 를 이용해서 Excel 파일을 그대로 ALV로 띄울 수 있습니다. 별도 테이블 정의 없이도 Excel의 첫 행을 헤더로 인식해서 동적 internal table을 만들어주고, SALV factory로 그대로 출력하면 끝.
이 글은 Excel 파일 → 동적 itab → SALV ALV 흐름을 한 화면 ABAP 프로그램으로 구현하는 패턴을 정리한 메모입니다.
핵심 원리
흐름은 5단계로 깔끔합니다.
| 단계 | 처리 | 핵심 API |
|---|---|---|
| 1 | 파일 선택 다이얼로그 | cl_gui_frontend_services=>file_open_dialog |
| 2 | 바이너리 업로드 + XSTRING 변환 | gui_upload + cl_bcs_convert=>solix_to_xstring |
| 3 | Excel 파싱 (XML 내부 변환) | cl_fdt_xl_spreadsheet 인스턴스 생성 |
| 4 | Worksheet → 동적 itab | get_itab_for_alv_update( ) + FIELD-SYMBOLS |
| 5 | ALV 표시 | cl_salv_table=>factory + 컬럼 헤더 설정 |
핵심 트릭은 cl_fdt_xl_spreadsheet 가 Excel의 첫 행을 헤더로 인식해서 동적 internal table 의 컬럼 구조를 자동으로 만들어준다 는 점입니다. 사용자가 어떤 Excel을 가져오든 별도 DDIC 정의 없이 그대로 표시됩니다.
⚠️ 중요한 제약: Excel 첫 행(헤더) 에 한글이 있으면 안 됩니다. 첫 행이 동적 itab의 컬럼명이 되는데, ABAP은 컬럼명에 한글을 허용하지 않으므로 첫 행은 영문/숫자/언더스코어로만 작성해야 합니다.
1단계 — 파일 선택 다이얼로그
사용자가 Excel 파일을 직접 선택하도록 다이얼로그를 띄웁니다. 필터를 *.xlsx 로 잡아두면 깔끔합니다.
DATA: lv_rc TYPE i,
it_files TYPE filetable,
lv_action TYPE i.
cl_gui_frontend_services=>file_open_dialog(
EXPORTING
file_filter = |xlsx (*.xlsx)\|*.xlsx\||
&& |{ cl_gui_frontend_services=>filetype_all }|
CHANGING
file_table = it_files
rc = lv_rc
user_action = lv_action ).
IF lv_action <> cl_gui_frontend_services=>action_ok OR lines( it_files ) = 0.
RETURN. " 사용자 취소 또는 파일 미선택
ENDIF.
선택된 파일 경로는 it_files[ 1 ]-filename 에 담깁니다.
2단계 — 바이너리 업로드 + XSTRING 변환
Excel은 텍스트 파일이 아니라 ZIP 기반 바이너리(XLSX) 입니다. 반드시 filetype = 'BIN' 으로 업로드해야 합니다.
DATA: lv_filesize TYPE w3param-cont_len,
it_bin_data TYPE w3mimetabtype.
cl_gui_frontend_services=>gui_upload(
EXPORTING
filename = |{ it_files[ 1 ]-filename }|
filetype = 'BIN' " 바이너리 모드 필수
IMPORTING
filelength = lv_filesize
CHANGING
data_tab = it_bin_data ).
" SOLIX 테이블 → XSTRING 변환
DATA(lv_bin_data) = cl_bcs_convert=>solix_to_xstring( it_solix = it_bin_data ).
gui_upload 결과는 SOLIX(바이너리 라인 테이블) 형식이라 cl_bcs_convert=>solix_to_xstring 으로 XSTRING 으로 변환해서 다음 단계로 넘김.
3단계 — Excel 파싱 (cl_fdt_xl_spreadsheet)
XSTRING으로 받은 Excel 바이너리를 cl_fdt_xl_spreadsheet 인스턴스에 넘기면 내부에서 XML 으로 풀어내고 워크시트 단위로 접근할 수 있게 해줍니다.
" Excel (itab) → XML → 객체 참조
" 주의: 메모리 사용 큼 · 느림 — 대용량 데이터는 부적합
DATA(o_excel) = NEW cl_fdt_xl_spreadsheet(
document_name = CONV #( it_files[ 1 ]-filename )
xdocument = lv_bin_data ).
" 워크시트 이름 목록 조회
DATA: it_worksheet_names TYPE if_fdt_doc_spreadsheet=>t_worksheet_names.
o_excel->if_fdt_doc_spreadsheet~get_worksheet_names(
IMPORTING worksheet_names = it_worksheet_names ).
핵심 포인트:
document_name— 파일명(확장자 포함)xdocument— XSTRING 바이너리if_fdt_doc_spreadsheet인터페이스로 워크시트 목록·데이터 접근
원래 NetWeaver 의 BRFplus 모듈에서 사용하던 내부 유틸리티지만, 일반 ABAP에서도 그대로 호출 가능합니다.
4단계 — Worksheet → 동적 itab
특정 워크시트의 데이터를 ALV용 동적 internal table 로 변환합니다. get_itab_for_alv_update( ) 가 핵심 메서드.
IF lines( it_worksheet_names ) > 0.
" 첫 워크시트의 itab 참조 가져오기
DATA(o_worksheet_itab) = o_excel->if_fdt_doc_spreadsheet~get_itab_for_alv_update( ).
" 동적 데이터 객체 → field-symbol 매핑
ASSIGN o_worksheet_itab->* TO FIELD-SYMBOL(<worksheet>).
...
ENDIF.
이 한 줄로 끝납니다. <worksheet> 는 Excel 첫 행을 헤더로 한 동적 internal table 입니다. 별도 TYPES 선언이 전혀 필요 없습니다. 컬럼 개수·이름이 매번 다른 Excel을 그대로 처리할 수 있다는 게 이 패턴의 큰 강점.
5단계 — SALV factory로 ALV 표시 + 헤더 정리
cl_salv_table=>factory 는 동적 internal table도 그대로 받아서 ALV를 생성해줍니다.

TRY.
DATA: o_salv TYPE REF TO cl_salv_table.
cl_salv_table=>factory(
IMPORTING
r_salv_table = o_salv
CHANGING
t_table = <worksheet> ).
" 기본 설정
o_salv->get_functions( )->set_all( abap_true ).
o_salv->get_columns( )->set_optimize( abap_true ).
o_salv->get_display_settings( )->set_list_header( 'Worksheet' ).
o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
o_salv->get_selections( )->set_selection_mode(
if_salv_c_selection_mode=>row_column ).
" 컬럼 헤더 텍스트 — 기술명을 long text 로 표시
LOOP AT o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
DATA(o_col) = <c>-r_column.
o_col->set_short_text( || ).
o_col->set_medium_text( || ).
o_col->set_long_text( |{ o_col->get_columnname( ) }| ).
ENDLOOP.
o_salv->display( ).
CATCH cx_root INTO DATA(e_txt).
WRITE: / e_txt->get_text( ).
ENDTRY.
핵심 포인트:
get_functions( )->set_all( abap_true )— 표준 ALV 버튼(정렬·필터·합계 등) 전부 활성화set_optimize( abap_true )— 컬럼 너비 자동 맞춤set_striped_pattern( abap_true )— 줄 무늬 배경- 컬럼 헤더 LOOP — 기본은 컬럼 기술명이 short/medium 으로만 나와서 줄어 보이므로
set_long_text에 풀 컬럼명을 박아 가독성 확보
전체 코드 (한 화면 정리)
위 5단계를 한 프로그램에 합치면 다음과 같습니다.
TRY.
DATA: lv_rc TYPE i,
it_files TYPE filetable,
lv_action TYPE i.
" 1) 파일 선택
cl_gui_frontend_services=>file_open_dialog(
EXPORTING
file_filter = |xlsx (*.xlsx)\|*.xlsx\||
&& |{ cl_gui_frontend_services=>filetype_all }|
CHANGING
file_table = it_files
rc = lv_rc
user_action = lv_action ).
IF lv_action = cl_gui_frontend_services=>action_ok.
IF lines( it_files ) > 0.
" 2) 바이너리 업로드
DATA: lv_filesize TYPE w3param-cont_len,
it_bin_data TYPE w3mimetabtype.
cl_gui_frontend_services=>gui_upload(
EXPORTING
filename = |{ it_files[ 1 ]-filename }|
filetype = 'BIN'
IMPORTING
filelength = lv_filesize
CHANGING
data_tab = it_bin_data ).
DATA(lv_bin_data) = cl_bcs_convert=>solix_to_xstring( it_solix = it_bin_data ).
" 3) Excel 파싱
DATA(o_excel) = NEW cl_fdt_xl_spreadsheet(
document_name = CONV #( it_files[ 1 ]-filename )
xdocument = lv_bin_data ).
DATA: it_worksheet_names TYPE if_fdt_doc_spreadsheet=>t_worksheet_names.
o_excel->if_fdt_doc_spreadsheet~get_worksheet_names(
IMPORTING worksheet_names = it_worksheet_names ).
IF lines( it_worksheet_names ) > 0.
" 4) 첫 워크시트 → 동적 itab
DATA(o_worksheet_itab) = o_excel->if_fdt_doc_spreadsheet~get_itab_for_alv_update( ).
ASSIGN o_worksheet_itab->* TO FIELD-SYMBOL(<worksheet>).
" 5) SALV 표시
TRY.
DATA: o_salv TYPE REF TO cl_salv_table.
cl_salv_table=>factory(
IMPORTING
r_salv_table = o_salv
CHANGING
t_table = <worksheet> ).
o_salv->get_functions( )->set_all( abap_true ).
o_salv->get_columns( )->set_optimize( abap_true ).
o_salv->get_display_settings( )->set_list_header( 'Worksheet' ).
o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
o_salv->get_selections( )->set_selection_mode(
if_salv_c_selection_mode=>row_column ).
LOOP AT o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
DATA(o_col) = <c>-r_column.
o_col->set_short_text( || ).
o_col->set_medium_text( || ).
o_col->set_long_text( |{ o_col->get_columnname( ) }| ).
ENDLOOP.
o_salv->display( ).
CATCH cx_root INTO DATA(e_txt).
WRITE: / e_txt->get_text( ).
ENDTRY.
ENDIF.
ENDIF.
ENDIF.
CATCH cx_root INTO DATA(e_text).
MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.
복붙해서 SE38에 그대로 넣고 활성화하면 즉시 동작하는 한 화면짜리 유틸리티 프로그램이 됩니다.
흔히 빠뜨리는 함정
Excel 첫 줄에 한글 사용
가장 흔한 함정. cl_fdt_xl_spreadsheet 는 Excel 첫 행을 동적 internal table 의 컬럼명으로 사용합니다. ABAP은 컬럼명에 한글을 허용하지 않으므로, 첫 행은 반드시 영문·숫자·언더스코어만 사용. 컬럼 이름은 영문으로, 한글 라벨이 필요하면 SALV 컬럼 LOOP에서 set_long_text 에 별도로 박아주는 방식.
gui_upload 에서 filetype = 'ASC' 사용
Excel(XLSX) 은 ZIP 기반 바이너리. 'ASC'(텍스트) 모드로 읽으면 깨진 데이터가 들어오고 cl_fdt_xl_spreadsheet 가 파싱 실패. 반드시 'BIN'.
대용량 Excel — 메모리 폭발 위험
Notion 원문 코멘트에도 명시되어 있는 부분 — Speicherintensiv und rel. langsam!(메모리 사용 크고 느림). cl_fdt_xl_spreadsheet 는 Excel 전체를 메모리에 XML로 풀어내는 방식이라 수만 행 이상 대용량은 부적합. 그런 경우는 TEXT_CONVERT_XLS_TO_SAP(텍스트 변환) 또는 ABAP2XLSX 같은 라이브러리 사용.
여러 워크시트가 있는 경우 첫 시트만 처리됨
get_itab_for_alv_update( ) 는 기본적으로 첫 워크시트만 가져옵니다. 다른 시트가 필요하면 it_worksheet_names 를 조회한 뒤 get_worksheet_data 같은 다른 메서드로 시트별 처리.
Excel 셀 자료형이 모두 문자열로 들어옴
cl_fdt_xl_spreadsheet 가 만드는 동적 itab은 모든 컬럼이 문자열 타입입니다. ALV로 단순 보기만 할 때는 문제 없지만, 후속 처리(예: 합계·정렬) 가 필요하면 수동으로 NUMC/DEC 변환 필요.
서버 잡(SM37)에서 실행 불가
file_open_dialog / gui_upload 는 SAP GUI 클라이언트에서만 동작. 배치 잡에서는 사용 불가. 서버에서 처리할 경우 OPEN DATASET + AL11(서버 디렉토리) 로 파일을 먼저 읽은 뒤 처리.
요약
| 단계 | 처리 | 핵심 |
|---|---|---|
| 1 | 파일 선택 | file_open_dialog + xlsx 필터 |
| 2 | 바이너리 업로드 | gui_upload (BIN) → solix_to_xstring |
| 3 | Excel 파싱 | NEW cl_fdt_xl_spreadsheet( document_name, xdocument ) |
| 4 | 동적 itab | get_itab_for_alv_update( ) + FIELD-SYMBOL |
| 5 | ALV 표시 | cl_salv_table=>factory + 컬럼 LOOP 으로 long text 채우기 |
이 패턴의 가장 큰 가치는 DDIC 정의·CBO 테이블 없이도 Excel을 그대로 ALV로 띄울 수 있다 는 점입니다. 사용자가 보낸 임의 형식 Excel을 검토하거나, 간단한 분석·검증·테스트 데이터 비교에 매우 유용합니다. 단, Excel 첫 행 한글 금지·대용량 부적합 두 가지 제약만 기억해두면 한 번 만든 프로그램을 사내 공용 유틸리티로 두고두고 쓸 수 있습니다.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다. cl_fdt_xl_spreadsheet 는 SAP NetWeaver 7.40 이상에서 사용 가능하며, SAP GUI 클라이언트 환경에서만 동작합니다. 대용량 Excel 처리에는 부적합하므로 운영 환경 적용 전 데이터 규모를 고려해 검증하시기 바랍니다.