REPORT zpj_xml_parse.

TYPE-POOLS: ixml.
CLASS cl_ixml DEFINITION LOAD.

CONSTANTS: c_tab(1) TYPE x VALUE '09',
           c_break(2) TYPE x VALUE '0D0A'.

TYPES: BEGIN OF t_xml_line,
        data(256) TYPE x,
      END OF t_xml_line.

DATA: g_ixml            TYPE REF TO if_ixml,
      g_streamfactory   TYPE REF TO if_ixml_stream_factory,
      g_parser          TYPE REF TO if_ixml_parser,
      g_istream         TYPE REF TO if_ixml_istream,
      g_document        TYPE REF TO if_ixml_document,
      g_node            TYPE REF TO if_ixml_node,
      g_xmldata         TYPE string,
      g_error           TYPE xfeld.

DATA: g_elem            TYPE REF TO if_ixml_element,
      g_root_node       TYPE REF TO if_ixml_node,
      g_next_node       TYPE REF TO if_ixml_node,
      g_name            TYPE string,
      g_iterator        TYPE REF TO if_ixml_node_iterator.

DATA: g_xml_table       TYPE TABLE OF t_xml_line,
      g_xml_line        TYPE t_xml_line,
      g_xml_table_size  TYPE i.

* Validation of XML file: Only DTD included in xml document is supported
*PARAMETERS: pa_val  TYPE char1 AS CHECKBOX.

****************************************
* screen selection                     *
****************************************
SELECTION-SCREEN: BEGIN OF BLOCK b0 WITH FRAME TITLE text-000.
SELECTION-SCREEN: BEGIN OF BLOCK b2 WITH FRAME TITLE text-002.
PARAMETERS: p_input LIKE rlgrap-filename DEFAULT 'C:\temp\flights2.xml'.
SELECTION-SCREEN: END OF BLOCK b2.
SELECTION-SCREEN: END OF BLOCK b0.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_input.
  PERFORM get_file_name USING ',*.XML.' CHANGING p_input.

****************************************
* START OF SELECTION                   *
****************************************
START-OF-SELECTION.

*   Creating the main iXML factory
  g_ixml = cl_ixml=>create( ).

*   Creating a stream factory
  g_streamfactory = g_ixml->create_stream_factory( ).

  PERFORM get_xml_table CHANGING g_xml_table_size g_xml_table.


*   wrap the table containing the file into a stream
  g_istream = g_streamfactory->create_istream_itable(
                                        table = g_xml_table
                                        size  = g_xml_table_size ).

*   Creating a document
  g_document = g_ixml->create_document( ).

*   Parse document
  PERFORM parse_document.
  CHECK g_error = space.

*   Process the document
  IF g_parser->is_dom_generating( ) EQ 'X'.
    PERFORM process_dom USING g_document.
  ENDIF.

*---------------------------------------------------------------------*
*       FORM parse_document                                           *
*---------------------------------------------------------------------*
FORM parse_document.
  DATA: parseerror TYPE REF TO if_ixml_parse_error,
        str        TYPE string,
        i          TYPE i,
        count      TYPE i,
        index      TYPE i.

*   Create a Parser
  g_parser = g_ixml->create_parser( stream_factory = g_streamfactory
                                    istream        = g_istream
                                    document       = g_document ).

*   Validate a document
*    IF pa_val EQ 'X'.
*      g_parser->set_validating( mode = if_ixml_parser=>co_validate ).
*    ENDIF.

*   Parse the stream
  IF g_parser->parse( ) NE 0.
    g_error = 'X'.
    IF g_parser->num_errors( ) NE 0.
      count = g_parser->num_errors( ).
      ULINE.
      WRITE: count, ' parse errors have occured:'.
      index = 0.
      WHILE index < count.
        parseerror = g_parser->get_error( index = index ).
        i = parseerror->get_line( ).
        WRITE: 'line: ', i.
        i = parseerror->get_column( ).
        WRITE: 'column: ', i.
        str = parseerror->get_reason( ).
        WRITE: str.
        index = index + 1.
      ENDWHILE.
    ENDIF.
  ENDIF.
ENDFORM.

*---------------------------------------------------------------------*
*       FORM get_xml_table                                            *
*---------------------------------------------------------------------*
FORM get_xml_table CHANGING g_xml_table_size TYPE i
                            g_xml_table      TYPE STANDARD TABLE.

*   Local variable declaration
  DATA: l_len      TYPE i,
        l_content  TYPE string,
        l_str1     TYPE string,
*         c_conv     TYPE REF TO cl_abap_conv_in_ce,
        l_itab     TYPE TABLE OF string,
        l_filename        TYPE string.

  l_filename = p_input.
*   upload a file from the client's workstation
  CALL METHOD cl_gui_frontend_services=>gui_upload
    EXPORTING
      filename   = l_filename
      filetype   = 'BIN'
    IMPORTING
      filelength = g_xml_table_size
    CHANGING
      data_tab   = g_xml_table
    EXCEPTIONS
      OTHERS     = 19.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

*   Writing the XML document to the screen
  CLEAR l_str1.
  LOOP AT g_xml_table INTO g_xml_line.
*      c_conv = cl_abap_conv_in_ce=>create( input = l_xml_line-data
*                                          replacement = space  ).
*      c_conv->read( IMPORTING data = l_content len = l_len ).
    l_content = g_xml_line.
    CONDENSE l_content.
    CONCATENATE l_str1 l_content INTO l_str1.
  ENDLOOP.

  l_len = strlen( l_str1 ).
  IF g_xml_table_size < l_len.
    l_len = g_xml_table_size.
  ENDIF.
  l_str1 = l_str1+0(l_len).

  SPLIT l_str1 AT c_break INTO TABLE l_itab.
  WRITE: /.
  WRITE: /' XML File'.
  WRITE: /.
  LOOP AT l_itab INTO l_str1.
*      REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>horizontal_tab
*       IN l_str1 WITH space.
    DO.
      REPLACE c_tab WITH space INTO l_str1.
      IF sy-subrc <> 0.
        EXIT.
      ENDIF.
    ENDDO.

    WRITE: / l_str1.
  ENDLOOP.
  WRITE: /.
ENDFORM.                    "get_xml_table

*---------------------------------------------------------------------*
*       FORM process_dom                                              *
*---------------------------------------------------------------------*
FORM process_dom USING document TYPE REF TO if_ixml_document.

  DATA: node      TYPE REF TO if_ixml_node,
        iterator  TYPE REF TO if_ixml_node_iterator,
        nodemap   TYPE REF TO if_ixml_named_node_map,
        attr      TYPE REF TO if_ixml_node,
        name      TYPE string,
        prefix    TYPE string,
        value     TYPE string,
        indent    TYPE i,
        count     TYPE i,
        index     TYPE i.


  node ?= document.

  CHECK NOT node IS INITIAL.

  ULINE.
  WRITE: /.
  WRITE: /' DOM-TREE'.
  WRITE: /.
  IF node IS INITIAL. EXIT. ENDIF.
*   create a node iterator
  iterator  = node->create_iterator( ).
*   get current node
  node = iterator->get_next( ).

*   loop over all nodes
  WHILE NOT node IS INITIAL.
    indent = node->get_height( ) * 2.
    indent = indent + 20.

    CASE node->get_type( ).
      WHEN if_ixml_node=>co_node_element.
*         element node
        name    = node->get_name( ).
        nodemap = node->get_attributes( ).
        WRITE: / 'ELEMENT  :'.
        WRITE: AT indent name COLOR COL_POSITIVE INVERSE.
        IF NOT nodemap IS INITIAL.
*           attributes
          count = nodemap->get_length( ).
          DO count TIMES.
            index  = sy-index - 1.
            attr   = nodemap->get_item( index ).
            name   = attr->get_name( ).
*              prefix = attr->get_namespace_prefix( ).
            value  = attr->get_value( ).
            WRITE: / 'ATTRIBUTE:'.
            WRITE: AT indent name  COLOR COL_HEADING INVERSE, '=',
                             value COLOR COL_TOTAL   INVERSE.
          ENDDO.
        ENDIF.
      WHEN if_ixml_node=>co_node_text OR
           if_ixml_node=>co_node_cdata_section.
*         text node
        value  = node->get_value( ).
        WRITE: / 'VALUE    :'.
        WRITE: AT indent value COLOR COL_GROUP INVERSE.
    ENDCASE.
*     advance to next node
    node = iterator->get_next( ).
  ENDWHILE.
ENDFORM.                    "process_dom

*---------------------------------------------------------------------*
*       FORM get_file_name                                            *
*---------------------------------------------------------------------*
FORM get_file_name USING p_mask
                   CHANGING p_file LIKE rlgrap-filename.
  CALL FUNCTION 'WS_FILENAME_GET'
       EXPORTING
            def_filename     = p_file
            def_path         = 'C:\'
            mask             = p_mask
            mode             = '0'
            title            = ''
       IMPORTING
            filename         = p_file
       EXCEPTIONS
            inv_winsys       = 1
            no_batch         = 2
            selection_cancel = 3
            selection_error  = 4
            OTHERS           = 5.
ENDFORM.