Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Convert XML string to internal table

Former Member
0 Kudos

Hi

My web service call returns a string XML. My task is to retrieve the values in the different nodes, preferably in an internal table. Previous I have used Simple Transformation, but I am not sure if this is possible this time, since the structure of the XML is changing (nodes can come 1 to n times).

Question: Are there any FMs that can convert my string XML to internal tables? What is the best practice to do in this situation?

regards Ole

7 REPLIES 7

amit_khare
Active Contributor
0 Kudos

Try this solution -

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.

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

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

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.

&----


*& 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

Regards,

Amit

Reward all helpful replies.

0 Kudos

Hi

Thanks for your reply.

I have already seen this solution. The question then is: how can I transform my string XML to an XML in a binary table? Do you have any idea?

I am not working with a fininshed XML file, so I need to skip the first step in this proposed solution...

-Ole

0 Kudos
Hi,
You can use cl_bcs_convert=>string_to_xstring  To convert your string  . 
And then do the xml stuf.  example:

TYPES: BEGIN OF tp_alv_data_1 .

TYPES: date        TYPE char32 ,
       name        TYPE char32 ,
       currency    TYPE char32 ,
       country     TYPE char32 ,
       rate        TYPE char32 ,
       ukurs       TYPE tcurr-ukurs ,
       change      TYPE char32 .
TYPES: END OF tp_alv_data_1 .

*

TYPES: tp_alv_data_1_tab TYPE STANDARD TABLE OF tp_alv_data_1  .


DATA: it_alv_data_1 TYPE tp_alv_data_1_tab  .

*----------------------------------------------------------------------*
FORM do_xml_parse_1
  USING
    xml_string TYPE xstring
  CHANGING
    it_alv_data_1 TYPE tp_alv_data_1_tab .

  IF xml_string IS INITIAL .
    RETURN .
  ENDIF .

  DATA: st_alv_data_1 LIKE LINE OF it_alv_data_1 .

  g_ixml = cl_ixml=>create( ).

  DATA: streamfactory TYPE REF TO if_ixml_stream_factory.

  streamfactory = g_ixml->create_stream_factory( ).

  DATA: istream TYPE REF TO if_ixml_istream.

  istream  = streamfactory->create_istream_xstring( string = xml_string ).

  DATA: document TYPE REF TO if_ixml_document.

  document = g_ixml->create_document( ) .

  DATA: parser TYPE REF TO if_ixml_parser.

  parser = g_ixml->create_parser( stream_factory = streamfactory
                                  istream        = istream
                                  document       = document ).

  parser->parse( ).

*------------------------------

  DATA: date  TYPE string .
  DATA: name  TYPE string .
  DATA: value TYPE string .

*------------------------------

  DATA: nodes_x TYPE REF TO if_ixml_node_collection .
  DATA: node_x  TYPE REF TO if_ixml_node .

  nodes_x = document->get_elements_by_tag_name( name = 'LAST_UPDATE' ).

  node_x = nodes_x->get_item( 0 ) .

  name  = node_x->get_name( ) .
  date  = node_x->get_value( ) .

  st_alv_data_1-date = node_x->get_value( ) .

*------------------------------

  DATA: length_0 TYPE i .
  DATA: nodes_0 TYPE REF TO if_ixml_node_collection.
  DATA: node_0  TYPE REF TO if_ixml_node .

  DATA: length_1 TYPE i .
  DATA: nodes_1 TYPE REF TO if_ixml_node_list .
  DATA: node_1  TYPE REF TO if_ixml_node .

  nodes_0 = document->get_elements_by_tag_name( name = 'CURRENCY' ).
  length_0 = nodes_0->get_length( ) .

  DATA: index TYPE i .

  DO length_0 TIMES .

    index = sy-index - 1 .

    node_0 = nodes_0->get_item( index ) .

    name  = node_0->get_name( ) .
    value = space .

    nodes_1 = node_0->get_children( ) .
    length_1 = nodes_1->get_length( ).

    DO length_1 TIMES .

      index = sy-index - 1 .

      node_1 = nodes_1->get_item( index ).

      name  = node_1->get_name( ) .
      value = node_1->get_value( ) .

      CASE name .
        WHEN 'NAME' .
          st_alv_data_1-name = value .
        WHEN 'CURRENCYCODE' .
          st_alv_data_1-currency = value .
        WHEN 'COUNTRY' .
          st_alv_data_1-country = value .
        WHEN 'RATE' .
          st_alv_data_1-rate  = value .
          st_alv_data_1-ukurs = value .
        WHEN 'CHANGE' .
          st_alv_data_1-change = value .
      ENDCASE .

    ENDDO .

    APPEND st_alv_data_1 TO it_alv_data_1 .

  ENDDO .

ENDFORM .                    "do_xml_parse_1
*----------------------------------------------------------------------*

     Regards.

Former Member
0 Kudos

Hi,

Try the following. These are the general practices. Hope the best one helps you.

You can write code like similar...

DATA xml_string TYPE string.

DATA source1(10) TYPE c VALUE 'Field1'.

DATA source2(10) TYPE c VALUE 'Field2'.

CALL TRANSFORMATION ...

SOURCE root1 = source1

root2 = source2

RESULT XML xml_string.

For more help see

http://help.sap.com/saphelp_nw04/helpdata/en/e3/7d4719ca581441b6841f1054ff1326/content.htm

Or You can look for this option below:

Check these standard demo transactions:

SXSLTDEMO1

SSTDEMO1

SSTDEMO2

Here you can see an example how export data from ABAP to XML and XML data to ABAP.

Thanks,

Samantak.

<b>Rewards points for useful answers.</b>

Former Member
0 Kudos

This message was moderated.

venkat_aileni
Contributor
0 Kudos

Hi-

To convert XML data to Internal tables you can use below sample code:

**//TABLES AND DATATYPES DECLARATION

TYPE-POOLS: abap, ixml.

**// WORKAREA TO HOLD XML DATA //**

TYPES: BEGIN OF ty_xdata,

str(2550) TYPE c,

END OF ty_xdata.

DATA : xdata TYPE STANDARD TABLE OF ty_xdata,

wa_xdata TYPE ty_xdata.

**// INTERNAL TABLE AND WORKAREA OF TYPE DATABASE TABLE

DATA: lt_itemp TYPE STANDARD TABLE OF zcitrus_table1,

wa_itemp TYPE zcitrus_table1,

gt_itemp TYPE STANDARD TABLE OF zcitrus_table1,

gs_itemp TYPE zcitrus_table1.

DATA: lt_itemp_g TYPE STANDARD TABLE OF zcitrus_table,

wa_itemp_g TYPE zcitrus_table,

gt_itemp_g TYPE STANDARD TABLE OF zcitrus_table,

gs_itemp_g TYPE zcitrus_table.

DATA : xmlupl TYPE string, " STRING VARIABLE USED FOR CONCATINATION

v_file TYPE string, " STRING VARIABLE TO HOLD FILE PATH

xstring TYPE xstring. " VARIABLE TO HOLD XSTRING DATA

**// PARAMETERS REQUIRED FOR FM SMUM_XML_PARSER

DATA : itab TYPE STANDARD TABLE OF smum_xmltb WITH HEADER LINE,

wa_itab LIKE itab,

return TYPE STANDARD TABLE OF bapiret2 .

START-OF-SELECTION.

**// PARAMETER TO HOLD FILE PATH

PARAMETERS : p_file TYPE rlgrap-filename OBLIGATORY.

**// PERFORMING VALIDATIONS ON P_FILE

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.

CALL FUNCTION 'F4_FILENAME'

EXPORTING

program_name = syst-cprog

dynpro_number = syst-dynnr

* FIELD_NAME = ' '

IMPORTING

file_name = p_file.

v_file = p_file.

**// UPLOADING DATA FROM THE FILE //**

IF v_file IS NOT INITIAL.

CALL FUNCTION 'GUI_UPLOAD'

EXPORTING

filename = v_file

filetype = 'ASC'

TABLES

data_tab = xdata.

ENDIF.

**// MOVING XML DATA TO THE XMLUPL //**

LOOP AT xdata INTO wa_xdata.

CONCATENATE xmlupl wa_xdata-str INTO xmlupl.

ENDLOOP.

**// FUNCTION MODULE TO CONVERT STRING TO XSTRING //**

CALL FUNCTION 'SCMS_STRING_TO_XSTRING'

EXPORTING

text = xmlupl

mimetype = 'SPACE '

* ENCODING =

IMPORTING

buffer = xstring

EXCEPTIONS

failed = 1

OTHERS = 2.

**// FUNCTION MODULE TO UPLOAD DATA TO INTERNAL TABLE //**

CALL FUNCTION 'SMUM_XML_PARSE'

EXPORTING

xml_input = xstring

TABLES

xml_table = itab[]

return = return.

Thanks,

Venkat

0 Kudos

Thank you. It was very helpful for me.