IT WORK/SAP FI and ABAP

[ABAP] XML to JSON

Bathildis 2024. 3. 20. 14:44
반응형
*&---------------------------------------------------------------------*
*& Report  YXMLTOJSON
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT YXMLTOJSON.

SELECTION-SCREEN: BEGIN OF BLOCK B2 WITH FRAME.
PARAMETERS : P_FILE LIKE RLGRAP-FILENAME OBLIGATORY.
SELECTION-SCREEN: END OF BLOCK B2.

*Select the file from the Local system
AT SELECTION-SCREEN ON VALUE-REQUEST FOR P_FILE.
  DATA: DIRECTORY TYPE STRING,
        FILETABLE TYPE FILETABLE,
        LINE      TYPE LINE OF FILETABLE,
        RC        TYPE I.
  CALL METHOD CL_GUI_FRONTEND_SERVICES=>GET_TEMP_DIRECTORY
    CHANGING
      TEMP_DIR = DIRECTORY.
  CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG
    EXPORTING
      WINDOW_TITLE      = 'SELECT THE FILE'
      INITIAL_DIRECTORY = DIRECTORY
      FILE_FILTER       = '*.xml'
      MULTISELECTION    = ' '
    CHANGING
      FILE_TABLE        = FILETABLE
      RC                = RC.
  IF RC = 1.
    READ TABLE FILETABLE INDEX 1 INTO LINE.
    P_FILE = LINE-FILENAME.
  ENDIF.


START-OF-SELECTION.

  DATA : BEGIN OF XMLTAB OCCURS 0,
           f(255) TYPE C,
         END OF XMLTAB.
  DATA : XMLSTR TYPE STRING.

  DATA : LV_PATH TYPE STRING.

  LV_PATH = P_FILE.

  CALL FUNCTION 'GUI_UPLOAD'
    EXPORTING
      FILENAME = LV_PATH
      FILETYPE = 'ASC'
    TABLES
      DATA_TAB = XMLTAB.

  LOOP AT XMLTAB.
    CONCATENATE XMLSTR XMLTAB-F INTO XMLSTR.
  ENDLOOP.


  TYPES: BEGIN OF NODE,
           NODE_TYPE TYPE IF_SXML_NODE=>NODE_TYPE,
           NAME      TYPE STRING,
           VALUE     TYPE STRING,
           ARRAY     TYPE C LENGTH 1,
         END OF NODE.
  DATA NODES TYPE TABLE OF NODE WITH EMPTY KEY.

  DATA(XML_STRING) = XMLSTR.

  DATA(XML) = CL_ABAP_CODEPAGE=>CONVERT_TO(
    REPLACE( VAL = XML_STRING SUB = |\n| WITH = `` OCC = 0  ) ).

  DATA(OUT) = CL_DEMO_OUTPUT=>NEW( )->BEGIN_SECTION( `XML-Data` )->WRITE_XML( XML ).

  "Parsing XML into an internal table
  DATA(READER) = CL_SXML_STRING_READER=>CREATE( XML ).
  CLEAR NODES.
  TRY.
      DO.
        READER->NEXT_NODE( ).
        IF READER->NODE_TYPE = IF_SXML_NODE=>CO_NT_FINAL.
          EXIT.
        ENDIF.
        APPEND VALUE #(
          NODE_TYPE  = READER->NODE_TYPE
          NAME       = READER->PREFIX &&
                       COND STRING(
                         WHEN READER->PREFIX IS NOT INITIAL
                              THEN `:` ) && READER->NAME
          VALUE      = READER->VALUE ) TO NODES.
        IF READER->NODE_TYPE = IF_SXML_NODE=>CO_NT_ELEMENT_OPEN.
          DO.
            READER->NEXT_ATTRIBUTE( ).
            IF READER->NODE_TYPE <> IF_SXML_NODE=>CO_NT_ATTRIBUTE.
              EXIT.
            ENDIF.
            APPEND VALUE #(
              NODE_TYPE = IF_SXML_NODE=>CO_NT_INITIAL
              NAME       = READER->PREFIX &&
                           COND STRING(
                             WHEN READER->PREFIX IS NOT INITIAL
                               THEN `:` ) && READER->NAME
              VALUE      = READER->VALUE ) TO NODES.
          ENDDO.
        ENDIF.
      ENDDO.
    CATCH CX_SXML_PARSE_ERROR INTO DATA(PARSE_ERROR).
      OUT->WRITE_TEXT( PARSE_ERROR->GET_TEXT( ) ).
  ENDTRY.

  "Determine the array limits in the internal table
  LOOP AT NODES ASSIGNING FIELD-SYMBOL(<NODE_OPEN>)
                WHERE
                 NODE_TYPE = IF_SXML_NODE=>CO_NT_ELEMENT_OPEN
                 AND ARRAY IS INITIAL.
    DATA(IDX_OPEN) = SY-TABIX.
    LOOP AT NODES ASSIGNING FIELD-SYMBOL(<NODE_CLOSE>)
                  FROM IDX_OPEN  + 1
                  WHERE
                    NODE_TYPE = IF_SXML_NODE=>CO_NT_ELEMENT_CLOSE
                    AND NAME = <NODE_OPEN>-NAME.
      DATA(IDX_CLOSE) = SY-TABIX.
      IF IDX_CLOSE < LINES( NODES ).
        ASSIGN NODES[ IDX_CLOSE + 1 ] TO FIELD-SYMBOL(<NODE>).
        IF <NODE>-NODE_TYPE = IF_SXML_NODE=>CO_NT_ELEMENT_OPEN AND
           <NODE>-NAME = <NODE_OPEN>-NAME.
          <NODE_OPEN>-ARRAY = 'O'.
          <NODE>-ARRAY = '_'.
        ELSEIF
          ( <NODE>-NODE_TYPE = IF_SXML_NODE=>CO_NT_ELEMENT_OPEN
            AND <NODE>-NAME <> <NODE_OPEN>-NAME )
          OR <NODE>-NODE_TYPE = IF_SXML_NODE=>CO_NT_ELEMENT_CLOSE.
          <NODE_CLOSE>-ARRAY = COND #(
            WHEN <NODE_OPEN>-ARRAY = 'O' THEN 'C' ).
          EXIT.
        ENDIF.
      ENDIF.
    ENDLOOP.
  ENDLOOP.
  "out->begin_section( `Nodes`
  ")->write( nodes ).

  "Render the internal table to JSON-XML
  DATA(WRITER) = CAST IF_SXML_WRITER(
   CL_SXML_STRING_WRITER=>CREATE( TYPE = IF_SXML=>CO_XT_JSON ) ).
  "create( type = if_sxml=>co_xt_xml10 ) ).
  TRY.
      WRITER->OPEN_ELEMENT( NAME = 'object' ).
      LOOP AT NODES ASSIGNING <NODE>.
        CASE <NODE>-NODE_TYPE.
          WHEN IF_SXML_NODE=>CO_NT_ELEMENT_OPEN.
            IF <NODE>-ARRAY IS INITIAL.
              WRITER->OPEN_ELEMENT( NAME = 'object' ).
              WRITER->WRITE_ATTRIBUTE( NAME = 'name'
                                       VALUE = <NODE>-NAME ).
            ELSEIF <NODE>-ARRAY = 'O'.
              WRITER->OPEN_ELEMENT( NAME = 'array' ).
              WRITER->WRITE_ATTRIBUTE( NAME = 'name'
                                       VALUE = <NODE>-NAME ).
              WRITER->OPEN_ELEMENT( NAME = 'object' ).
            ELSEIF <NODE>-ARRAY = '_'.
              WRITER->OPEN_ELEMENT( NAME = 'object' ).
            ENDIF.
          WHEN IF_SXML_NODE=>CO_NT_ELEMENT_CLOSE.
            IF <NODE>-ARRAY <> 'C'.
              WRITER->CLOSE_ELEMENT( ).
            ELSE.
              WRITER->CLOSE_ELEMENT( ).
              WRITER->CLOSE_ELEMENT( ).
            ENDIF.
          WHEN IF_SXML_NODE=>CO_NT_INITIAL.
            WRITER->OPEN_ELEMENT( NAME = 'str' ).
            WRITER->WRITE_ATTRIBUTE( NAME = 'name'
                                     VALUE = `a_` && <NODE>-NAME ).
            WRITER->WRITE_VALUE( <NODE>-VALUE ).
            WRITER->CLOSE_ELEMENT( ).
          WHEN IF_SXML_NODE=>CO_NT_VALUE.
            WRITER->OPEN_ELEMENT( NAME = 'str' ).
            WRITER->WRITE_ATTRIBUTE( NAME = 'name'
                                     VALUE = `e_` && <NODE>-NAME ).
            WRITER->WRITE_VALUE( <NODE>-VALUE ).
            WRITER->CLOSE_ELEMENT( ).
          WHEN OTHERS.
            OUT->DISPLAY( 'A node type is not yet supported' ).
            RETURN.
        ENDCASE.
      ENDLOOP.
      WRITER->CLOSE_ELEMENT( ).

      DATA(JSON) =
        CAST CL_SXML_STRING_WRITER( WRITER )->GET_OUTPUT( ).

      OUT->NEXT_SECTION( 'JSON-Data' ).
      IF WRITER->IF_SXML~TYPE = IF_SXML=>CO_XT_JSON.
        OUT->WRITE_JSON( JSON ).
      ELSEIF WRITER->IF_SXML~TYPE = IF_SXML=>CO_XT_XML10.
        OUT->WRITE_XML( JSON ).
      ENDIF.

    CATCH CX_SXML_ERROR INTO DATA(EXC).
      OUT->WRITE( EXC->GET_TEXT( ) ).
  ENDTRY.

  OUT->DISPLAY( ).
반응형