This is a test message to test the length of the message box.
Login
ABAP Cloud XML
Created by Software-Heroes

ABAP Cloud - Create XML

548

How can you actually create an XML in ABAP Cloud outside of transformations? In this article, we'll recreate an XML in detail.



In an older article, we looked at how to read an XML stream. In this article, we will delve into the details of creating it and assemble the structure from last time step by step.

 

Introduction

From time to time, we also need to process XML files and streams in ABAP, perhaps because we receive them from file processing or, in the ABAP Cloud world, send them as a payload to a service that doesn't understand JSON. In addition to transformations, SAP also offers various released ABAP APIs in the system that we can use to implement this. The challenge with transformations is that they require a separate skill set to learn the syntax behind them.

In this article, we want to recreate the structure from the last article. The structure contains various components, such as its own namespace, attributes, and values at different levels.

 

Hint: You can find an explanation of the individual components of XML in the article linked above to better understand the structure of XML.

 

Start

In the first step, we need a configuration and some data to begin implementation. We will use the same type from the last article, which we will create locally in the class.

TYPES: BEGIN OF people,
         height TYPE c LENGTH 9,
         name   TYPE string,
       END OF people.
TYPES peoples TYPE STANDARD TABLE OF people WITH EMPTY KEY.

TYPES: BEGIN OF file,
         head_key         TYPE c LENGTH 10,
         head_description TYPE string,
         title            TYPE string,
         description      TYPE string,
         desc_length      TYPE i,
         desc_space       TYPE c LENGTH 20,
         tags             TYPE string,
         peoples          TYPE peoples,
       END OF file.

 

We then fill in the configuration and pass it to the generation function, which then creates the XML for us. The data in our example would then look like this.

DATA(setting) = VALUE file( head_key         = 'H1'
                            head_description = `My custom XML`
                            title            = `First try`
                            description      = `A description text`
                            desc_length      = 25
                            desc_space       = 'minimum'
                            tags             = `Name, Data, Others`
                            peoples          = VALUE #( ( height = '150cm' name = `Jason` )
                                                        ( height = '155cm' name = `Pamela` )
                                                        ( height = '190cm' name = `Ryan` ) ) ).

 

Implementation

In this chapter, we'll cover mapping and implementation. We'll use the CL_SXML_STRING_WRITER class to generate our XML. In the following sections, we'll discuss the various special features.

 

Writer

To begin creating, we'll create a String Writer object. We only need this locally and create it as a local variable.

DATA(string_writer) = cl_sxml_string_writer=>create( ).
writer = CAST if_sxml_writer( string_writer ).

 

The string writer has a relatively small number of methods and is primarily used to create the file. Therefore, we need to perform a CAST on IF_SXML_WRITER. We store the instance as an attribute in the class, since we want to access it from the various methods. In principle, you can also pass the instance from method to method.

 

The interface provides most of the methods we need to work with the XML object.

 

Structure

To process our structure, we map the various steps as methods and call them one after the other. This breaks down the large task into smaller components and allows us to process the mapping node by node.

open_root( ).
add_title( ).
add_description( ).
add_people( ).
add_tags( ).
close_node( ).

 

We create the CLOSE_NODE method centrally because we need it multiple times to close a node, making it easier to reuse as a function. The method creates a closing element and writes it to the object via the WRITER.

writer->write_node( writer->new_close_element( ) ).

 

Node with Attributes

Our root node consists of a namespace and two attributes. Accordingly, we have the WRITER create a new opening element and pass the name, namespace, and namespace prefix. We can use the created object to set the attributes and their values. To adopt the node, we call the WRITE_NODE method at the end and pass our object.

DATA(open_node) = writer->new_open_element( name   = `myroot`
                                            nsuri  = namespace_swh
                                            prefix = prefix_swh ).
open_node->set_attribute( name  = `key`
                          value = run_setting-title ).
open_node->set_attribute( name  = `description`
                          value = run_setting-description ).
writer->write_node( open_node ).

 

If we execute the previous logic (root node and closing), we currently get the following result in the form of our first node.

<swh:myroot key="First try" description="A description text" xmlns:swh="http://software-heroes/swh"/>

 

The namespace has been adopted into the node, and we can also find all the attributes. We can now begin creating the other nodes in the same format.

 

Node with Value

What happens now when we want to write a value? The value is located between the two tags. In this example, we create the TITLE tag and adopt the node into the model. In the next step, we create a node for the value using NEW_VALUE, adopt the value using SET_VALUE, and add it as well. Finally, we close the current node.

DATA(open_node) = writer->new_open_element( name   = `title`
                                            nsuri  = namespace_swh
                                            prefix = prefix_swh ).
writer->write_node( open_node ).

DATA(value_node) = writer->new_value( ).
value_node->set_value( run_setting-title ).
writer->write_node( value_node ).

close_node( ).

 

Finish

Once we have created all the information and nodes, we can call the GET_OUTPUT method on the original object, which returns the XML as a binary. We then convert the content into a readable string using the XCO class. Before we return the result for verification, we add the XML tag at the beginning; unfortunately, this is not generated.

DATA(binary) = string_writer->get_output( ).
DATA(content) = xco_cp=>xstring( binary )->as_string( xco_cp_character=>code_page->utf_8 )->value.

RETURN |<?xml version="1.0" encoding="UTF-8"?>{ content }|.

 

If we look at the result, you should now have the following output. In this case, we rendered the result in the browser, since the class returns the string unformatted.

 

Options

In the last step, we added the header manually to the stream; this mainly affects older releases. Starting with release 2502, it is now possible to generate the header, with or without encoding. The following two constants are available for this purpose:

  • IF_SXML_WRITER=>CO_OPT_VAL_FULL generates the complete header (<?xml version="1.0" encoding="utf-8"?>)
  • IF_SXML_WRITER=>CO_OPT_VAL_WITHOUT_ENCODING generates the output without the corresponding encoding (IF_SXML_WRITER=>CO_OPT_VAL_FULL)

 

In our example, we can define additional output options in addition to the header. For example, if we set line breaks and indentation, we can also output the result to the console.

writer->set_option( option = if_sxml_writer=>co_opt_xml_header
                    value  = if_sxml_writer=>co_opt_val_full ).

writer->set_option( option = if_sxml_writer=>co_opt_linebreaks
                    value  = abap_true ).

writer->set_option( option = if_sxml_writer=>co_opt_indent
                    value  = abap_true ).

 

In the ABAP console, the final result would then look like this.

 

Complete Example

We haven't covered all the details of the conversion in this article. However, you can find the complete class here if you want to test it in your system or are looking for more information about the class.

CLASS zcl_bs_demo_xml_create DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PRIVATE SECTION.
    TYPES: BEGIN OF people,
             height TYPE c LENGTH 9,
             name   TYPE string,
           END OF people.
    TYPES peoples TYPE STANDARD TABLE OF people WITH EMPTY KEY.

    TYPES: BEGIN OF file,
             head_key         TYPE c LENGTH 10,
             head_description TYPE string,
             title            TYPE string,
             description      TYPE string,
             desc_length      TYPE i,
             desc_space       TYPE c LENGTH 20,
             tags             TYPE string,
             peoples          TYPE peoples,
           END OF file.

    CONSTANTS namespace_swh TYPE string VALUE `http://software-heroes/swh`.
    CONSTANTS prefix_swh    TYPE string VALUE `swh`.

    DATA run_setting TYPE file.
    DATA writer      TYPE REF TO if_sxml_writer.

    METHODS create_xml_content
      IMPORTING run_setting   TYPE file
      RETURNING VALUE(result) TYPE string.

    METHODS add_person
      IMPORTING !person TYPE zcl_bs_demo_xml_create=>people.

    METHODS close_node.
    METHODS open_root.
    METHODS add_title.
    METHODS add_description.
    METHODS add_people.
    METHODS add_tags.
    METHODS set_writer_options.

ENDCLASS.


CLASS zcl_bs_demo_xml_create IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    DATA(setting) = VALUE file( head_key         = 'H1'
                                head_description = `My custom XML`
                                title            = `First try`
                                description      = `A description text`
                                desc_length      = 25
                                desc_space       = 'minimum'
                                tags             = `Name, Data, Others`
                                peoples          = VALUE #( ( height = '150cm' name = `Jason` )
                                                            ( height = '155cm' name = `Pamela` )
                                                            ( height = '190cm' name = `Ryan` ) ) ).

    out->write( create_xml_content( setting ) ).
  ENDMETHOD.


  METHOD create_xml_content.
    me->run_setting = run_setting.

    DATA(string_writer) = cl_sxml_string_writer=>create( ).
    writer = CAST if_sxml_writer( string_writer ).

    set_writer_options( ).

    open_root( ).
    add_title( ).
    add_description( ).
    add_people( ).
    add_tags( ).
    close_node( ).

    DATA(binary) = string_writer->get_output( ).
    DATA(content) = xco_cp=>xstring( binary )->as_string( xco_cp_character=>code_page->utf_8 )->value.

    " RETURN |<?xml version="1.0" encoding="UTF-8"?>{ content }|.
    RETURN content.
  ENDMETHOD.


  METHOD set_writer_options.
    writer->set_option( option = if_sxml_writer=>co_opt_xml_header
                        value  = if_sxml_writer=>co_opt_val_full ).

    writer->set_option( option = if_sxml_writer=>co_opt_linebreaks
                        value  = abap_true ).

    writer->set_option( option = if_sxml_writer=>co_opt_indent
                        value  = abap_true ).
  ENDMETHOD.


  METHOD close_node.
    writer->write_node( writer->new_close_element( ) ).
  ENDMETHOD.


  METHOD open_root.
    DATA(open_node) = writer->new_open_element( name   = `myroot`
                                                nsuri  = namespace_swh
                                                prefix = prefix_swh ).
    open_node->set_attribute( name  = `key`
                              value = run_setting-title ).
    open_node->set_attribute( name  = `description`
                              value = run_setting-description ).
    writer->write_node( open_node ).
  ENDMETHOD.


  METHOD add_title.
    DATA(open_node) = writer->new_open_element( name   = `title`
                                                nsuri  = namespace_swh
                                                prefix = prefix_swh ).
    writer->write_node( open_node ).

    DATA(value_node) = writer->new_value( ).
    value_node->set_value( run_setting-title ).
    writer->write_node( value_node ).

    close_node( ).
  ENDMETHOD.


  METHOD add_description.
    DATA(open_node) = writer->new_open_element( name   = `description`
                                                nsuri  = namespace_swh
                                                prefix = prefix_swh ).
    open_node->set_attribute( name  = `length`
                              value = CONV #( run_setting-desc_length ) ).
    open_node->set_attribute( name  = `space`
                              value = CONV #( run_setting-desc_space ) ).
    writer->write_node( open_node ).

    DATA(value_node) = writer->new_value( ).
    value_node->set_value( run_setting-description ).
    writer->write_node( value_node ).

    close_node( ).
  ENDMETHOD.


  METHOD add_people.
    DATA(open_node) = writer->new_open_element( `table` ).
    writer->write_node( open_node ).

    LOOP AT run_setting-peoples INTO DATA(person).
      add_person( person ).
    ENDLOOP.

    close_node( ).
  ENDMETHOD.


  METHOD add_tags.
    DATA(open_node) = writer->new_open_element( name   = `tags`
                                                nsuri  = namespace_swh
                                                prefix = prefix_swh ).
    writer->write_node( open_node ).

    DATA(value_node) = writer->new_value( ).
    value_node->set_value( run_setting-tags ).
    writer->write_node( value_node ).

    close_node( ).
  ENDMETHOD.


  METHOD add_person.
    DATA(open_node) = writer->new_open_element( `item` ).
    open_node->set_attribute( name  = `height`
                              value = CONV #( person-height ) ).
    writer->write_node( open_node ).

    DATA(value_node) = writer->new_value( ).
    value_node->set_value( person-name ).
    writer->write_node( value_node ).

    close_node( ).
  ENDMETHOD.
ENDCLASS.

 

Conclusion

There are currently many things to learn in ABAP development. If you're new, you might find it difficult to learn everything at once. You can therefore choose to watch the class or familiarize yourself with the topic of transformation.

 

Further information:
SAP Help - sXML Rendering


Included topics:
ABAP CloudABAPXMLCreate XML
Comments (0)



And further ...

Are you satisfied with the content of the article? We post new content in the ABAP area every Friday and irregularly in all other areas. Take a look at our tools and apps, we provide them free of charge.


ABAP Cloud - Reusable Components

Category - ABAP

What points should you consider when developing reusable components in ABAP Cloud? Here we look at various examples.

04/18/2025

ABAP Cloud - Transport of the Software Component

Category - ABAP

What about the transport of software components in the ABAP Cloud? Do you also need the on-premise component in the test and production system?

03/11/2025

ABAP Cloud - CRV Update & TIER-3

Category - ABAP

How can you find the right API for your scenario in ABAP Cloud and what do you actually do with TIER-3 in your development? More information here.

02/25/2025

ABAP Cloud - Read XML

Category - ABAP

How can you read and process XML data relatively easily in ABAP Cloud? Let's look at an example and go through it step by step.

02/21/2025

ABAP Cloud - Clean Core (Scenarios)

Category - ABAP

In this article, let's take another look at the Clean Core architecture with ABAP Cloud, where it is used and where you can build your applications.

01/10/2025