FUNCTION z_xml_to_table.
*"----------------------------------------------------------------------
*"*"Local interface:
*"  IMPORTING
*"     REFERENCE(IV_XML) TYPE  STRING
*"     REFERENCE(IV_ROOT_NODE_NAME) TYPE  STRING OPTIONAL
*"  EXPORTING
*"     REFERENCE(E_DATA) TYPE  ANY
*"----------------------------------------------------------------------
* XML을 입력받아 인터널 테이블 또는 스트럭처로 변환한다.
* 이름의 경우 XML은 대소문자 구분하지만 ABAP에서는 대문자로 변경하여 처리함.
* 예: <Row><col1>a</col1><col2>B<col2><Row>
* 변환: ROW[1]-COL1 = 'a', ROW[1]-COl2 = 'B'

  DATAlo_ixml           TYPE REF TO if_ixml,
        lo_stream_factory TYPE REF TO if_ixml_stream_factory,
        lo_istream        TYPE REF TO if_ixml_istream,
        lo_document       TYPE REF TO if_ixml_document,
        lo_parser         TYPE REF TO if_ixml_parser,
        lo_node           TYPE REF TO if_ixml_node,
        lo_node_coll      TYPE REF TO if_ixml_node_collection,
        lo_node_list      TYPE REF TO if_ixml_node_list,
        lo_node_iterator  TYPE REF TO if_ixml_node_iterator,
        lv_flag_to_child  TYPE flag.

  CHECKiv_xml IS NOT INITIAL.
  lo_ixml cl_ixml=>create).
  lo_stream_factory lo_ixml->create_stream_factory).
  lo_istream lo_stream_factory->create_istream_cstringstring iv_xml ).
  lo_document lo_ixml->create_document).
  lo_parser lo_ixml->create_parser(
                document       lo_document
                istream        lo_istream
                stream_factory lo_stream_factory
  ).
  lo_parser->parse).

  IF iv_root_node_name IS NOT INITIAL.
    " 시작 노드 이름(IV_ROOT_NODE_NAME) 이 있으면
    lo_node_coll lo_document->get_elements_by_tag_name(
        name      iv_root_node_name
    ).
    lo_node_iterator lo_node_coll->create_iterator).
    lv_flag_to_child ''.
  ELSE.
    " 없으면 document 의 children 으로 시작.
    lo_node_list lo_document->get_children).
    lo_node_iterator lo_node_list->create_iterator).
    lv_flag_to_child 'X'.
  ENDIF.

  PERFORM xml_to_table_recursion
          USING lo_node_iterator
                lv_flag_to_child
          CHANGING e_data.


ENDFUNCTION.

*&---------------------------------------------------------------------*
*&      Form  xml_to_table_recursion
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->IO_NODE_ITERATOR  text
*      -->IV_FLAG_TO_CHILD  text
*      <--C_DATA            text
*----------------------------------------------------------------------*
FORM xml_to_table_recursion  USING    io_node_iterator TYPE REF TO if_ixml_node_iterator
                                      iv_flag_to_child TYPE flag
                             CHANGING c_data TYPE any.
  DATAlo_node           TYPE REF TO if_ixml_node,
        lo_node_coll      TYPE REF TO if_ixml_node_collection,
        lo_node_list      TYPE REF TO if_ixml_node_list,
        lo_node_attrs     TYPE REF TO if_ixml_named_node_map,
        lo_node_iterator  TYPE REF TO if_ixml_node_iterator,
        lv_c_data_type    TYPE c,
        lv_node_type      TYPE i,
        lv_node_name      TYPE string,
        lv_node_value     TYPE string.
  FIELD-SYMBOLS<lt_data> TYPE table,
                 <ls_data> TYPE data,
                 <l_data> TYPE data.

  DESCRIBE FIELD c_data TYPE lv_c_data_type.
  IF lv_c_data_type EQ 'h'" h : Internal table , u v : structure
    " 인터널 테이블 이면 빈줄 하나 추가하여 진행한다.
    ASSIGN c_data TO <lt_data>.
    APPEND INITIAL LINE TO <lt_data> ASSIGNING <ls_data>.
  ELSE.
    ASSIGN c_data TO <ls_data>.
  ENDIF.

  DO.
    lo_node io_node_iterator->get_next).
    IF lo_node IS INITIAL.
      EXIT.
    ENDIF.

    lv_node_type lo_node->get_type).
    CASE lv_node_type.
      WHEN if_ixml_node=>co_node_element.
        " 노드 엘리먼트
        lv_node_name lo_node->get_name).
        TRANSLATE lv_node_name TO UPPER CASE" 노드 이름을 대문자로
        IF iv_flag_to_child IS NOT INITIAL" true
          ASSIGN COMPONENT lv_node_name OF STRUCTURE <ls_data> TO <l_data>.
          CHECKsy-subrc EQ 0.   " 이름이 일치하는 필드가 없으면 무시.
        ELSE.
          ASSIGN <ls_data> TO <l_data>.
        ENDIF.

        " 자식 노드
        lo_node_list lo_node->get_children).
        IF lo_node_list->get_length0.
          lo_node_iterator lo_node_list->create_iterator).
          PERFORM xml_to_table_recursion
                  USING lo_node_iterator
                        'X'
                  CHANGING <l_data>.
        ENDIF.

        " 어트리뷰트
        lo_node_attrs lo_node->get_attributes).
        IF lo_node_attrs->get_length0.
          lo_node_iterator lo_node_attrs->create_iterator).
          PERFORM xml_to_table_recursion
                  USING lo_node_iterator
                        'X'
                  CHANGING <l_data>.
        ENDIF.

      WHEN if_ixml_node=>co_node_text OR if_ixml_node=>co_node_cdata_section.
        " 텍스트 값
        lv_node_value lo_node->get_value).
        <ls_data> lv_node_value.

      WHEN if_ixml_node=>co_node_attribute.
        " 노드 어트리뷰트
        lv_node_name lo_node->get_name).
        TRANSLATE lv_node_name TO UPPER CASE" 노드 이름을 대문자로
        ASSIGN COMPONENT lv_node_name OF STRUCTURE <ls_data> TO <l_data>.
        CHECKsy-subrc EQ 0.   " 이름이 일치하는 필드가 없으면 무시.
        lv_node_value lo_node->get_value).
        <l_data> lv_node_value.

      WHEN OTHERS.
        " 기타: 무시
    ENDCASE.

  ENDDO.

ENDFORM.                    " XML_TO_TABLE_RECURSION