Convert an XML file into an ABAP table using SAP DOM Approach

本文介绍如何使用SAP XML Document Object Model (DOM)将本地XML文件的数据读取并存储到ABAP内部表中。通过上传XML文件创建二进制表,并使用iXML工厂解析成DOM对象,最后遍历节点填充ABAP表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址: http://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/2702

 

XML DOM Processing in ABAP part II - Convert an XML file into an ABAP table using SAP DOM Approach.

 

Introduction

In this weblog I will focus on the possibilities of SAP XML Document Object Model (DOM) processing at the ABAP stack. My objective is to explain how you can use it in abap mapping. For this I split this weblog into three parts. This document is the second-in-the-series and will focus on the conversion from a XML file (back) to an ABAP table. This first part focused on the conversion of an ABAP table into an XML file and the last part will deal with the use of SAP DOM within XI ABAP mapping, introduced with SAP XI 3.0.

The XML

In this weblog we will focus on retrieving data from a local XML file and store it in an internal table.
We will start with an upload of a local XML file into a binary XML table and we will bind it to a XML input stream.
image

Next we will parse the stream to a XML DOM object using a using an iXML factory.
image

And finally we have a XML DOM Object and we can access its nodes to fill our table.
image

The implementation

In the implementation we will explain the steps of the process and at the end of the log you will find a complete source sample.
To upload the XML file, you need the filename and you have to declare an internal binary table to store the uploaded XML file.

  TYPES: t_xml_line(1024) TYPE x.
 
  DATA: l_filename        TYPE string,
        l_xml_table       TYPE TABLE OF t_xml_line,
        l_xml_line        TYPE t_xml_line,
        l_xml_table_size  TYPE i.
        

    CALL METHOD cl_gui_frontend_services=>gui_upload
      EXPORTING
        filename   = l_filename
        filetype   = 'BIN'
      IMPORTING
        filelength = l_xml_table_size
      CHANGING
        data_tab   = l_xml_table
      EXCEPTIONS
        OTHERS     = 1.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
                 WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.


When you have the XML file in a binary table, you can start to process the XML data. To do this we need an iXML factory which will help us create an input stream from the binary table.  

 TYPE-POOLS: ixml.
 DATA: l_ixml TYPE REF TO if_ixml.
 l_ixml = cl_ixml=>create( ).



This iXML factory can create a XML stream factory which actually creates an input stream based on the binary table.

 DATA: l_streamfactory   TYPE REF TO if_ixml_stream_factory,
       l_istream         TYPE REF TO if_ixml_istream.

 l_streamfactory = l_ixml->create_stream_factory( ).

 l_istream = l_streamfactory->create_istream_itable(
                                table = l_xml_table
                                size  = l_xml_table_size ).



Before creating the XML DOM object you have to create an empty document and a parser object. The document object will represent the DOM object and the parser is needed to convert the XML stream into a XML DOM object.

 DATA:  l_document TYPE REF TO if_ixml_document,
         l_parser    TYPE REF TO if_ixml_parser.

 l_document = l_ixml->create_document( ).
 l_parser = l_ixml->create_parser(
                      stream_factory = l_streamfactory
                      istream        = l_istream
                      document       = l_document ).



After having created the parser, the empty document and the input stream, you can start the conversion using the parse method of the parser. If the parsing failes, you  can retrieve the error using the if_xml_parse_error interface.

 DATA: l_parse_error TYPE REF TO if_ixml_parse_error.

 IF l_parser->parse( ) NE 0.
  IF l_parser->num_errors( ) NE 0.
   ...
   l_parse_error = l_parser->get_error( index = l_index ).
   ...
  ENDIF.
 ENDIF.

At this point you have to check if the DOM was really created and if so you can process the document.

 IF l_parser->is_dom_generating( ) EQ 'X'.
  PERFORM process_dom USING l_document.
 ENDIF.


To process it you need to cast the document to a node interface object.

 DATA: node      TYPE REF TO if_ixml_node,
       iterator  TYPE REF TO if_ixml_node_iterator.

 node ?= document.

 CHECK NOT node IS INITIAL.


When having the DOM object as a node object, you can use an iterator to “walk” trough the DOM object. To do this you have to create the iterator of the node object and get the root node using the get_next method of the iterator.

 iterator  = node->create_iterator( ).
 node = iterator->get_next( ).


Scrolling through the DOM, you can fill your internal table. The method get_type will tell you if the node is an element- of a text node.  In the element node you will find the name of the element and the attribute which belong to the element node. In the text node, you will find the value of the element node.

 WHILE NOT node IS INITIAL.
  CASE node->get_type( ).
   WHEN if_ixml_node=>co_node_element.
    name  = node->get_name( ).
    ...
   WHEN if_ixml_node=>co_node_text OR
        if_ixml_node=>co_node_cdata_section.
    value = node->get_value( ).
    ...
  ENDCASE.
  node = iterator->get_next( ).
 ENDWHILE.


The attributes of an element will be available in a node map with the interface if_ixml_named_node_map. This interface can be used to read the names and values of the attributes in the element.

 nodemap = node->get_attributes( ).
 IF NOT nodemap IS INITIAL.
  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( ).
   ...
  ENDDO.
 ENDIF.


This finished the second step-of-three. As mentioned before the next log will focus on the use of SAP DOM within XI ABAP mapping.

A complete example

*&---------------------------------------------------------------------*
*& Report  z_xit_xml_check
*&---------------------------------------------------------------------*
  REPORT  z_xit_xml_check.

  TYPE-POOLS: ixml.

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

  DATA: l_ixml            TYPE REF TO if_ixml,
        l_streamfactory   TYPE REF TO if_ixml_stream_factory,
        l_parser          TYPE REF TO if_ixml_parser,
        l_istream         TYPE REF TO if_ixml_istream,
        l_document        TYPE REF TO if_ixml_document,
        l_node            TYPE REF TO if_ixml_node,
        l_xmldata         TYPE string.

  DATA: l_elem            TYPE REF TO if_ixml_element,
        l_root_node       TYPE REF TO if_ixml_node,
        l_next_node       TYPE REF TO if_ixml_node,
        l_name            TYPE string,
        l_iterator        TYPE REF TO if_ixml_node_iterator.

  DATA: l_xml_table       TYPE TABLE OF t_xml_line,
        l_xml_line        TYPE t_xml_line,
        l_xml_table_size  TYPE i.
  DATA: l_filename        TYPE string.


  PARAMETERS: pa_file TYPE char1024 DEFAULT 'c:/temp/orders_dtd.xml'.
* Validation of XML file: Only DTD included in xml document is supported
  PARAMETERS: pa_val  TYPE char1 AS CHECKBOX.

  START-OF-SELECTION.

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

*   Creating a stream factory
    l_streamfactory = l_ixml->create_stream_factory( ).

    PERFORM get_xml_table CHANGING l_xml_table_size l_xml_table.


*   wrap the table containing the file into a stream
    l_istream = l_streamfactory->create_istream_itable( table = l_xml_table
                                                    size  = l_xml_table_size ).

*   Creating a document
    l_document = l_ixml->create_document( ).

*   Create a Parser
    l_parser = l_ixml->create_parser( stream_factory = l_streamfactory
                                      istream        = l_istream
                                      document       = l_document ).

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

*   Parse the stream
    IF l_parser->parse( ) NE 0.
      IF l_parser->num_errors( ) NE 0.
        DATA: parseerror TYPE REF TO if_ixml_parse_error,
              str        TYPE string,
              i          TYPE i,
              count      TYPE i,
              index      TYPE i.

        count = l_parser->num_errors( ).
        WRITE: count, ' parse errors have occured:'.
        index = 0.
        WHILE index < count.
          parseerror = l_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.

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


*&--------------------------------------------------------------------*
*&      Form  get_xml_table
*&--------------------------------------------------------------------*
  FORM get_xml_table CHANGING l_xml_table_size TYPE i
                              l_xml_table      TYPE STANDARD TABLE.

*   Local variable declaration
    DATA: l_len      TYPE i,
          l_len2     TYPE i,
          l_tab      TYPE tsfixml,
          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 = pa_file.
*   upload a file from the client's workstation
    CALL METHOD cl_gui_frontend_services=>gui_upload
      EXPORTING
        filename   = l_filename
        filetype   = 'BIN'
      IMPORTING
        filelength = l_xml_table_size
      CHANGING
        data_tab   = l_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 l_xml_table INTO l_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 ).
      CONCATENATE l_str1 l_content INTO l_str1.
    ENDLOOP.
    l_str1 = l_str1+0(l_xml_table_size).
    SPLIT l_str1 AT cl_abap_char_utilities=>cr_lf 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.
      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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值