[ABAP] XML -> String

DATA: xml TYPE string VALUE '<?xml version="1.0" encoding="utf-8"?><asx:abap version="1.0" xmlns:asx="http://www.sap.com/abapxml"><asx:values><TEXT>Hello world!</TEXT></asx:values></asx:abap>'.
DATA: text TYPE string.

* XML -> ABAP (string)
CALL TRANSFORMATION id SOURCE XML xml RESULT text = text.

WRITE: / text.

[ABAP] itab -> XML

TYPES: BEGIN OF s_person,
         name  TYPE string,
         title TYPE string,
         age   TYPE i,
       END OF s_person.

TYPES: t_person TYPE STANDARD TABLE OF s_person WITH DEFAULT KEY.

DATA(it_persons) = VALUE t_person( ( name = 'Horst' title = 'Herr' age = 30 )
                                   ( name = 'Jutta' title = 'Frau' age = 35 )
                                   ( name = 'Ingo' title = 'Herr' age = 31 ) ).

* ABAP (iTab) -> XML
DATA(o_writer_itab_xml) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 ).
CALL TRANSFORMATION id SOURCE values = it_persons RESULT XML o_writer_itab_xml.
DATA(itab_xml) = cl_abap_codepage=>convert_from( o_writer_itab_xml->get_output( ) ).

WRITE: / itab_xml.

[ABAP] XML -> itab

TYPES: BEGIN OF s_person,
         name  TYPE string,
         title TYPE string,
         age   TYPE i,
       END OF s_person.

TYPES: t_person TYPE STANDARD TABLE OF s_person WITH DEFAULT KEY.

DATA(xml) = |<?xml version="1.0" encoding="UTF-8"?>| &&
            |<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">| &&
            |  <asx:values>| &&
            |    <VALUES>| &&
            |      <item>| &&
            |        <NAME>Horst</NAME>| &&
            |        <TITLE>Herr</TITLE>| &&
            |        <AGE>30</AGE>| &&
            |      </item>| &&
            |      <item>| &&
            |        <NAME>Jutta</NAME>| &&
            |        <TITLE>Frau</TITLE>| &&
            |        <AGE>35</AGE>| &&
            |      </item>| &&
            |      <item>| &&
            |        <NAME>Ingo</NAME>| &&
            |        <TITLE>Herr</TITLE>| &&
            |        <AGE>31</AGE>| &&
            |      </item>| &&
            |    </VALUES>| &&
            |  </asx:values>| &&
            |</asx:abap>|.

* XML -> ABAP (itab)
DATA(it_persons) = VALUE t_person( ).

CALL TRANSFORMATION id SOURCE XML xml RESULT values = it_persons.

IF lines( it_persons ) > 0.
  WRITE: / it_persons[ 1 ]-name.
endif.

[ABAP] XML nach JSON parsen

* XML-Daten
DATA(lv_xml) = |<object><str name="text">abcd</str><bool name="flag">true</bool><member name="number"><num>111</num></member><member name="content"><null /></member></object>|.

TRY.
* XML-Daten lesen
    DATA(o_r) = cl_sxml_string_reader=>create( input = cl_abap_codepage=>convert_to( lv_xml ) ).
* evtl. Objektkomponenten mit <member->-Elementen darstellen
*    reader->set_option( if_sxml_reader=>co_opt_sep_member ).

    DATA(o_w) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type     = if_sxml=>co_xt_json
                                                                    encoding = 'UTF-8' ) ).
* Ausgabeoptionen setzen
    o_w->set_option( option = if_sxml_writer=>co_opt_linebreaks ).
    o_w->set_option( option = if_sxml_writer=>co_opt_indent ).

    o_r->next_node( ).
* JSON parsen
    o_r->skip_node( o_w ).

* Ausgabe konvertieren
    DATA(lv_json) = cl_abap_codepage=>convert_from( CAST cl_sxml_string_writer( o_w )->get_output( ) ).

* JSON ausgeben
    cl_demo_output=>display_json( lv_json ).
  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

[ABAP] DOM: Hilfs-Klasse zur Ausgabe von XML-Daten

Verwendung

DATA: o_xml_doc TYPE REF TO if_ixml_document.

* Erzeugt String aus DOM-XML-Document
DATA(lv_xml_string) = lcl_xml_tool=>get_xml_string_from_xml_doc( i_dom_xml_doc = o_xml_doc ).

* Gibt rekursiv alle Nodes unterhalb übergebener Node aus
lcl_xml_tool=>print_xml( o_xml_doc->get_root_element( ) ).

Klasse

CLASS lcl_xml_tool DEFINITION.
  PUBLIC SECTION.
  *--------------------------------------------------------------------*
    CLASS-METHODS: get_xml_string_from_xml_doc
      IMPORTING
                i_dom_xml_doc      TYPE REF TO if_ixml_document
                i_encoding         TYPE string DEFAULT 'UTF-8'
      RETURNING VALUE(ret_xml_str) TYPE string.
*--------------------------------------------------------------------*
    CLASS-METHODS: get_node_string
      IMPORTING
                i_dom_xml_node    TYPE REF TO if_ixml_node
                i_close           TYPE boolean
      RETURNING VALUE(ret_string) TYPE string.
*--------------------------------------------------------------------*
    CLASS-METHODS: print_xml
      IMPORTING
        i_dom_xml_root TYPE REF TO if_ixml_node.
*--------------------------------------------------------------------*
  PRIVATE SECTION.
    CONSTANTS: co_stretch_factor TYPE i VALUE 4.
ENDCLASS.
*--------------------------------------------------------------------*
CLASS lcl_xml_tool IMPLEMENTATION.
*--------------------------------------------------------------------*
* Erzeugt String aus DOM-XML-Document
*--------------------------------------------------------------------*
* -> i_dom_xml_doc - DOM-XML-Document
* -> i_encoding    - XML-Encoding
* <- ret_xml_str   - DOM-XML-Document als String
*--------------------------------------------------------------------*
  METHOD get_xml_string_from_xml_doc.

    ret_xml_str = ''.

    TRY.
        DATA(o_ixml) = cl_ixml=>create( ).
        DATA(o_sf) = o_ixml->create_stream_factory( ).
        DATA(o_encoding) = o_ixml->create_encoding( character_set = i_encoding
                                                    byte_order = if_ixml_encoding=>co_none ).

        DATA: lv_xml TYPE string.

        DATA(o_ostream) = o_sf->create_ostream_cstring( lv_xml ).
        o_ostream->set_encoding( encoding = o_encoding ).
        o_ostream->set_pretty_print( pretty_print = abap_true ).

        DATA(o_render) = o_ixml->create_renderer( ostream  = o_ostream
                                                  document = i_dom_xml_doc ).

* XML-String in lv_xml generieren
        DATA(lv_rc) = o_render->render( ).

* Dateigröße in Bytes
        DATA(lv_size) = o_ostream->get_num_written_raw( ).

* Stream schließen
        o_ostream->close( ).

        IF lv_rc = 0 AND lv_size > 0.
          ret_xml_str = lv_xml.
        ENDIF.
      CATCH cx_root.
    ENDTRY.

  ENDMETHOD.
*--------------------------------------------------------------------*
* Erzeugt String aus Node
*--------------------------------------------------------------------*
* -> i_dom_xml_node - Node
* -> i_close        - evtl. Schließen-Tag ausgeben
* <- ret_string     - Node-String
*--------------------------------------------------------------------*
  METHOD get_node_string.

    ret_string = ''.

    TRY.
        CASE i_dom_xml_node->get_type( ).
* Element
          WHEN if_ixml_node=>co_node_element.
            DATA(o_attr) = i_dom_xml_node->get_attributes( ).

            DATA: lv_attr TYPE string.

            IF o_attr IS BOUND.
              DATA(lv_attr_cnt) = o_attr->get_length( ).

* alle Attribute ausgeben
              DO lv_attr_cnt TIMES.
                DATA(o_attri_item) = o_attr->get_item( sy-index - 1 ).

* Namespace
                DATA(lv_namespace) = o_attri_item->get_namespace( ).
*                DATA(lv_prefix) = o_attri_item->get_namespace_prefix( ).

                DATA(lv_ns_attr) = lv_namespace.

* Namespace:Attribut
                IF NOT lv_ns_attr IS INITIAL.
                  lv_ns_attr = |{ lv_ns_attr }:{ o_attri_item->get_name( ) }|.
                else.
                  lv_ns_attr = |{ o_attri_item->get_name( ) }|.
                ENDIF.

                IF lv_attr IS INITIAL.
                  lv_attr = |{ lv_ns_attr }="{ o_attri_item->get_value( ) }"|.
                ELSE.
                  lv_attr = |{ lv_attr } { lv_ns_attr }="{ o_attri_item->get_value( ) }"|.
                ENDIF.
              ENDDO.
            ENDIF.

            IF i_close = abap_false.
              DATA(lv_close_tag) = |>|.
* Gibt es Unterelemente zur Node?
              IF i_dom_xml_node->get_first_child( ) IS INITIAL.
                lv_close_tag = |/>|.
              ENDIF.

              IF strlen( lv_attr ) = 0.
                ret_string = |<{ i_dom_xml_node->get_name( ) }{ lv_close_tag }|.
              ELSE.
                ret_string = |<{ i_dom_xml_node->get_name( ) } { lv_attr }{ lv_close_tag }|.
              ENDIF.
            ELSE.
              ret_string = |</{ i_dom_xml_node->get_name( ) }>|.
            ENDIF.
* Werte
          WHEN if_ixml_node=>co_node_text OR if_ixml_node=>co_node_cdata_section.
            ret_string = i_dom_xml_node->get_value( ).
        ENDCASE.
      CATCH cx_root.
    ENDTRY.

  ENDMETHOD.
*--------------------------------------------------------------------*
* Gibt rekursiv alle Nodes ab i_xml_root (Root) aus
*--------------------------------------------------------------------*
* -> i_dom_xml_root - Root-Node
*--------------------------------------------------------------------*
  METHOD print_xml.
* Einrückung
    DATA(lv_indent) = i_dom_xml_root->get_height( ) * co_stretch_factor.

    WRITE: / |{ ' ' WIDTH = lv_indent }{ get_node_string( i_dom_xml_node = i_dom_xml_root
                                                          i_close        = abap_false ) }|.

    DATA(o_node) = i_dom_xml_root->get_first_child( ).

    IF NOT o_node IS INITIAL.
* Wenn Childs vorhanden -> auflisten
      WHILE NOT o_node IS INITIAL.
        print_xml( o_node ).
        o_node = o_node->get_next( ).
      ENDWHILE.
* evtl. Schließ-Tag setzen
      WRITE: / |{ ' ' WIDTH = lv_indent }{ get_node_string( i_dom_xml_node = i_dom_xml_root
                                                            i_close        = abap_true ) }|.
    ENDIF.

  ENDMETHOD.

[ABAP] HTTP-Client Anfrage (cl_http_client)

Testprogramm: RSHTTP20

Variante 1 (URL)

TRY.
* URL
    DATA(lv_url) = |https://www.google.de/|.

    DATA: o_client TYPE REF TO if_http_client.

* Client-Objekt erzeugen
    cl_http_client=>create_by_url( EXPORTING
                                     url     = lv_url
                                   IMPORTING
                                     client  = o_client ).

    IF o_client IS BOUND.
* Anmeldedaten übermitteln
      o_client->authenticate( username = ''
                              password = '' ).

* Logon-Popup ein- bzw. ausschalten
      o_client->propertytype_logon_popup = o_client->co_enabled.

* HTTP-Prtotokoll-Version
      o_client->request->set_version( version = if_http_request=>co_protocol_version_1_1 ).
* HTTP-Method
      o_client->request->set_method( if_http_request=>co_request_method_get ).

* Header-Felder explizit setzen
*      o_client->request->set_header_field( name  = '~request_method'
*                                           value = 'GET' ).
*
*      o_client->request->set_header_field( name  = 'Content-Type'
*                                           value = 'text/xml; charset=utf-8' ).
*
*      o_client->request->set_header_field( name  = 'Accept'
*                                           value = 'text/xml, text/html' ).

* Cookies akzeptieren
      o_client->propertytype_accept_cookie = if_http_client=>co_enabled.
* Kompression akzeptieren
      o_client->propertytype_accept_compress = if_http_client=>co_enabled.

* HTTP GET senden, evtl. Timeout angeben
      o_client->send( timeout = if_http_client=>co_timeout_default ).

* Response lesen
      o_client->receive( ).

      DATA: lv_http_status TYPE i.
      DATA: lv_status_text TYPE string.

* HTTP Return Code holen
      o_client->response->get_status( IMPORTING
                                        code   = lv_http_status
                                        reason = lv_status_text ).

      WRITE: / 'HTTP_STATUS_CODE:', lv_http_status.
      WRITE: / 'STATUS_TEXT:', lv_status_text.

* Header-Daten der Übertragung
      WRITE: / 'HEADER_FIELDS:'.
      DATA(it_header_fields) = VALUE tihttpnvp( ).
      o_client->response->get_header_fields( CHANGING fields = it_header_fields ).

      LOOP AT it_header_fields ASSIGNING FIELD-SYMBOL(<f>).
        WRITE: / '[', <f>-name, ']', <f>-value.
      ENDLOOP.

* Cookies holen
      WRITE: / 'COOKIES:'.
      DATA(it_cookies) = VALUE tihttpcki( ).
      o_client->response->get_cookies( CHANGING cookies = it_cookies ).

      LOOP AT it_cookies ASSIGNING FIELD-SYMBOL(<c>).
        WRITE: / '[', <c>-name, ']', <c>-value, <c>-xdomain, <c>-path, <c>-secure, <c>-expires.
      ENDLOOP.

* vollständige HTTP Nachricht lesen
      DATA(lv_raw_message) = o_client->response->get_raw_message( ).
      DATA: lv_str_msg TYPE string.

* xstring -> string
      DATA(o_conv_r) = cl_abap_conv_in_ce=>create( input    = lv_raw_message
                                                   encoding = 'UTF-8' ).

      o_conv_r->read( IMPORTING data = lv_str_msg ).

      WRITE: / 'RAW MESSAGE:', lv_str_msg.

* Wenn Status 200 (Ok)
      IF lv_http_status = 200.
* HTTP Body als Character-Daten
        DATA(lv_result) = o_client->response->get_cdata( ).

        WRITE: / 'CDATA:'.
        WRITE: / lv_result.
      ENDIF.

* HTTP Connection schließen
      o_client->close( ).
    ENDIF.
  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

Variante 2 (HTTP-Alias)

* mit SM59 einrichten
DATA: lv_http_dest TYPE rfcdest VALUE 'HTTP_ALIAS'.

DATA: o_client TYPE REF TO if_http_client.

DATA: lv_http_rc TYPE i.
DATA: lv_reason TYPE string.

TRY.
    cl_http_client=>create_by_destination( EXPORTING
                                             destination = lv_http_dest
                                           IMPORTING
                                             client      = o_client ).

    o_client->request->set_method( if_http_request=>co_request_method_get ).

    o_client->send( ).

    o_client->receive( ).

    o_client->response->get_status( IMPORTING
                                      code   = lv_http_rc
                                      reason = lv_reason ).

    IF lv_http_rc = 200.
      DATA(lv_xml) = o_client->response->get_cdata( ).

      cl_abap_browser=>show_xml( xml_string = lv_xml
                                 title      = 'XML-Daten'
                                 size       = cl_abap_browser=>large ).
    ELSE.
      WRITE: / 'Fehler: ', lv_http_rc.
    ENDIF.

    o_client->close( ).

  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

[ABAP] Interne Tabellen im Format Office Open XML (SpreadsheetML) speichern

Beispiel für die Nutzung des Office Open XML (SpreadsheetML) Formates zur Datenausgabe von Nutzdaten aus internen Tabellen.

Links

Wikipedia – Office Open XML
Wikipedia – SpreadsheetML
SAP ABAP Doku
Beispiel 1
Beispiel 2

Beispiel – Speicherung Daten beliebiger interner Tabellen in eine von Microsoft Office Excel lesbare XML-Datei

* Dateien können ab Microsoft Office Excel 2002 / 2003 geöffnet werden
DATA: it_spfli TYPE STANDARD TABLE OF spfli.
DATA: gv_company TYPE string VALUE 'codezentrale.de'.
DATA: gv_user TYPE string VALUE 'Testuser'.
DATA: gv_sheetname TYPE string VALUE 'SPFLI'.

INITIALIZATION.
* Daten holen
  SELECT * FROM spfli INTO TABLE @it_spfli.

START-OF-SELECTION.

  DATA: o_cell TYPE REF TO if_ixml_element.
  DATA: o_data TYPE REF TO if_ixml_element.

* Tabellenstruktur
  DATA(o_table_descr) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data( it_spfli ) ).

* Struktur einer Tabellenzeile
  DATA(o_struct_descr) = CAST cl_abap_structdescr( o_table_descr->get_table_line_type( ) ).

* Komponenten (Spalten) einer Zeile
  DATA(it_comp_tab) = o_struct_descr->get_components( ).

* Anzahl Spalten
  DATA(lv_colcount) = lines( it_comp_tab ).

* ixml Factory
  DATA(o_ixml) = cl_ixml=>create( ).

* Encoding UTF-8
  DATA(o_encoding) = o_ixml->create_encoding( character_set = 'UTF-8'
                                              byte_order = if_ixml_encoding=>co_none ).

* DOM Object Model
  DATA(o_doc) = o_ixml->create_document( ).

* Processing Instructions setzen
* damit die XML-Datei gleich vom Windows als Excel-XML erkannt und korrekt geöffnet wird
  DATA(o_pi) = o_doc->create_pi_parsed( name = 'mso-application' ).
  o_pi->set_attribute( name = 'progid' value = 'Excel.Sheet' ).
  o_doc->append_child( o_pi ).

* Workbook
  DATA(o_workbook) = o_doc->create_simple_element( name = 'Workbook' parent = o_doc ).
  o_workbook->set_attribute( name = 'xmlns' value ='urn:schemas-microsoft-com:office:spreadsheet' ).
  o_workbook->set_attribute_node( o_doc->create_namespace_decl( name = 'o' prefix = 'xmlns' uri = 'urn:schemas-microsoft-com:office:office') ).
  o_workbook->set_attribute_node( o_doc->create_namespace_decl( name = 'x' prefix = 'xmlns' uri = 'urn:schemas-microsoft-com:office:excel' ) ).
  o_workbook->set_attribute_node( o_doc->create_namespace_decl( name = 'ss' prefix = 'xmlns' uri = 'urn:schemas-microsoft-com:office:spreadsheet') ).
  o_workbook->set_attribute_node( o_doc->create_namespace_decl( name = 'html' prefix = 'xmlns' uri = 'http://www.w3.org/TR/REC-html40') ).

* DocumentProperties
* Zeitstempel erzeugen
  DATA: lv_tsl TYPE timestampl.
  GET TIME STAMP FIELD lv_tsl.
  DATA(lv_created) = |{ substring( val = |{ lv_tsl TIMESTAMP = ISO }| off = 0 len = 19 ) }Z|.

  DATA(o_prop) = o_doc->create_simple_element( name = 'DocumentProperties' parent = o_workbook ).
  o_prop->set_attribute( name = 'xmlns' value ='urn:schemas-microsoft-com:office:office' ).
  o_doc->create_simple_element( name = 'Author' value = gv_user parent = o_prop ).
  o_doc->create_simple_element( name = 'LastAuthor' value = gv_user parent = o_prop ).
  o_doc->create_simple_element( name = 'Created' value = lv_created parent = o_prop ).
  o_doc->create_simple_element( name = 'Company' value = gv_company parent = o_prop ).
  o_doc->create_simple_element( name = 'Version' value = '14.00' parent = o_prop ).

* OfficeDocumentSettings
  DATA(o_set) = o_doc->create_simple_element( name = 'OfficeDocumentSettings' parent = o_workbook ).
  o_set->set_attribute( name = 'xmlns' value ='urn:schemas-microsoft-com:office:office' ).
  o_doc->create_simple_element( name = 'AllowPNG' parent = o_set ).

* ExcelWorkbook
  DATA(o_excelwb) = o_doc->create_simple_element( name = 'ExcelWorkbook' parent = o_workbook ).
  o_excelwb->set_attribute( name = 'xmlns' value ='urn:schemas-microsoft-com:office:excel' ).
  o_doc->create_simple_element( name = 'ProtectStructure' value = 'False' parent = o_excelwb ).
  o_doc->create_simple_element( name = 'ProtectWindows' value = 'False' parent = o_excelwb ).

* Styles
  DATA(o_styles) = o_doc->create_simple_element( name = 'Styles' parent = o_workbook ).

* "Default" Style
  DATA(o_style_default) = o_doc->create_simple_element( name = 'Style' parent = o_styles ).
  o_style_default->set_attribute_ns( name = 'ID' prefix = 'ss' value = 'Default' ).
  o_style_default->set_attribute_ns( name = 'Name' prefix = 'ss' value = 'Normal' ).
  DATA(o_align) = o_doc->create_simple_element( name = 'Alignment' parent = o_style_default ).
  o_align->set_attribute_ns( name = 'Vertical' prefix = 'ss' value = 'Bottom' ).
  DATA(o_borders) = o_doc->create_simple_element( name = 'Borders' parent = o_style_default ).
  DATA(o_font) = o_doc->create_simple_element( name = 'Font' parent = o_style_default ).
  o_font->set_attribute_ns( name = 'FontName' prefix = 'ss' value = 'Arial' ).
  o_font->set_attribute_ns( name = 'Family' prefix = 'x' value = 'Swiss' ).
  o_font->set_attribute_ns( name = 'Size' prefix = 'ss' value = '11' ).
  o_font->set_attribute_ns( name = 'Color' prefix = 'ss' value = '#000000' ).
  DATA(o_interior) = o_doc->create_simple_element( name = 'Interior' parent = o_style_default ).
  DATA(o_numberformat) = o_doc->create_simple_element( name = 'NumberFormat' parent = o_style_default ).
  DATA(o_protection) = o_doc->create_simple_element( name = 'Protection' parent = o_style_default ).

* Bold Style "s62" für die Überschrift
  DATA(o_style_bold) = o_doc->create_simple_element( name = 'Style' parent = o_styles ).
  o_style_bold->set_attribute_ns( name = 'ID' prefix = 'ss' value = 's62' ).
  DATA(o_font_bold) = o_doc->create_simple_element( name = 'Font' parent = o_style_bold ).
  o_font_bold->set_attribute_ns( name = 'FontName' prefix = 'ss' value = 'Arial' ).
  o_font_bold->set_attribute_ns( name = 'Family' prefix = 'x' value = 'Swiss' ).
  o_font_bold->set_attribute_ns( name = 'Size' prefix = 'ss' value = '11' ).
  o_font_bold->set_attribute_ns( name = 'Color' prefix = 'ss' value = '#000000' ).
  o_font_bold->set_attribute_ns( name = 'Bold' prefix = 'ss' value = '1' ).

* Worksheet "SPFLI" einfügen
  DATA(o_sheet1) = o_doc->create_simple_element( name = 'Worksheet' parent = o_workbook ).
  o_sheet1->set_attribute_ns( name = 'Name' prefix = 'ss' value = gv_sheetname ).

* WorksheetOptions
  DATA(o_ws_opt) = o_doc->create_simple_element( name = 'WorksheetOptions' parent = o_sheet1 ).
  o_ws_opt->set_attribute( name = 'xmlns' value = 'urn:schemas-microsoft-com:office:excel' ).

  o_doc->create_simple_element( name = 'Selected' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'ProtectObjects' value = 'False' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'ProtectScenarios' value = 'False' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'SplitHorizontal' value = '1' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'TopRowBottomPane' value = '1' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'FreezePanes' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'FrozenNoSplit' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'Unsynced' parent = o_ws_opt ).
  o_doc->create_simple_element( name = 'ActivePane' value = '2' parent = o_ws_opt ).

* Page Setup
  DATA(o_ps) = o_doc->create_simple_element( name = 'PageSetup' parent = o_ws_opt ).
  DATA(o_ps_header) = o_doc->create_simple_element( name = 'Header' parent = o_ps ).
  o_ps_header->set_attribute_ns( name = 'Margin' prefix = 'x' value = '0.3' ).
  DATA(o_ps_footer) = o_doc->create_simple_element( name = 'Footer' parent = o_ps ).
  o_ps_footer->set_attribute_ns( name = 'Margin' prefix = 'x' value = '0.3' ).
  DATA(o_ps_margins) = o_doc->create_simple_element( name = 'PageMargins' parent = o_ps ).
  o_ps_margins->set_attribute_ns( name = 'Bottom' prefix = 'x' value = '0.7' ).
  o_ps_margins->set_attribute_ns( name = 'Left' prefix = 'x' value = '0.7' ).
  o_ps_margins->set_attribute_ns( name = 'Right' prefix = 'x' value = '0.7' ).
  o_ps_margins->set_attribute_ns( name = 'Top' prefix = 'x' value = '0.7' ).

* Splitter für Header / Data definieren
  o_doc->create_simple_element( name = 'x:Selected' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:FreezePanes' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:FrozenNoSplit' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:Unsynced' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:ProtectObjects' value = 'False' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:ProtectScenarios' value = 'False' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:SplitHorizontal' value = '1' parent = o_ps ).
  o_doc->create_simple_element( name = 'x:TopRowBottomPane' value = '1' parent = o_ps ).

* Named Range für Filter definieren
  DATA(o_names) = o_doc->create_simple_element( name = 'Names' parent = o_sheet1 ).
  DATA(o_named_range) = o_doc->create_simple_element( name = 'NamedRange' parent = o_names ).
  o_named_range->set_attribute_ns( name = 'Name' prefix = 'ss' value = '_FilterDatabase' ).
  o_named_range->set_attribute_ns( name = 'RefersTo' prefix = 'ss' value = |=Sheet1!R1C1:R1C{ lv_colcount }| ). " Spalte 1-x als Range "_FilterDatabase" definieren
  o_named_range->set_attribute_ns( name = 'Hidden' prefix = 'ss' value = '1' ).

* Autofilter aktivieren
  DATA(o_autofilter) = o_doc->create_simple_element( name = 'AutoFilter' parent = o_sheet1 ).
  o_autofilter->set_attribute_ns( name = 'Range' prefix = 'x' value = |R1C1:R1C{ lv_colcount }| ).              " Spalte 1-x als Filter-Range definieren
  o_autofilter->set_attribute_ns( name = 'xmlns' value = 'urn:schemas-microsoft-com:office:excel' ).

* Table für Header und Daten
  DATA(o_table) = o_doc->create_simple_element( name = 'Table' parent = o_sheet1 ).
  o_table->set_attribute_ns( name = 'FullColumns' prefix = 'x' value = '1' ).
  o_table->set_attribute_ns( name = 'FullRows' prefix = 'x' value = '1' ).
  o_table->set_attribute_ns( name = 'DefaultColumnWidth' prefix = 'x' value = '66' ).
  o_table->set_attribute_ns( name = 'DefaultRowHeight' prefix = 'x' value = '14.25' ).
  o_table->set_attribute_ns( name = 'DefaultColumnWidth' prefix = 'ss' value = '66' ).
  o_table->set_attribute_ns( name = 'DefaultRowHeight' prefix = 'ss' value = '14.25' ).

* Header (Tabellenüberschriften) einfügen
  DATA(o_hrow) = o_doc->create_simple_element( name = 'Row' parent = o_table ).

  LOOP AT it_comp_tab ASSIGNING FIELD-SYMBOL(<fs_comp>).
    o_cell = o_doc->create_simple_element( name = 'Cell' parent = o_hrow ).
    o_cell->set_attribute_ns( name = 'StyleID' prefix = 'ss' value = 's62' ). " Style Bold
* nur elementare Datentypen zulassen
    IF <fs_comp>-type->kind = cl_abap_typedescr=>kind_elem.
      o_doc->create_simple_element( name = 'Data' value = <fs_comp>-name parent = o_cell )->set_attribute_ns( name = 'Type' prefix = 'ss' value = 'String' ).
    ELSE.
* alle anderen Spalten mit Strukturen, INCLUDES usw. einfach als DEEP kennzeichnen, Inhalt bleibt leer
      o_doc->create_simple_element( name = 'Data' value = 'DEEP' parent = o_cell )->set_attribute_ns( name = 'Type' prefix = 'ss' value = 'String' ).
    ENDIF.
* Named Range "_FilterDatabase" für Filter setzen
    o_doc->create_simple_element( name = 'NamedCell' parent = o_cell )->set_attribute_ns( name = 'Name' prefix = 'ss' value = '_FilterDatabase' ).
  ENDLOOP.

* Daten einfügen
  LOOP AT it_spfli ASSIGNING FIELD-SYMBOL(<fs_line>).
    DATA(o_row_data) = o_doc->create_simple_element( name = 'Row' parent = o_table ).

    o_struct_descr ?= cl_abap_structdescr=>describe_by_data( <fs_line> ).

    LOOP AT o_struct_descr->get_components( ) ASSIGNING FIELD-SYMBOL(<fs_comp2>).

      o_cell = o_doc->create_simple_element( name = 'Cell' parent = o_row_data ).

* nur elementare Datentypen zulassen, andernfalls gibts Exceptions bei der String-Konvertierung
* die Spalten mit kennzeichnung "DEEP" bleiben in der Ausgabe somit leer
      IF <fs_comp2>-type->kind = cl_abap_typedescr=>kind_elem.
        ASSIGN COMPONENT <fs_comp2>-name OF STRUCTURE <fs_line> TO FIELD-SYMBOL(<fs_cell>).

        IF <fs_cell> IS ASSIGNED.
          DATA: lv_data_type TYPE string.
          DATA(lv_typekind) = cl_abap_elemdescr=>get_data_type_kind( <fs_cell> ).

          CASE lv_typekind.
            WHEN cl_abap_typedescr=>typekind_time OR cl_abap_typedescr=>typekind_date OR cl_abap_typedescr=>typekind_string OR cl_abap_typedescr=>typekind_char.
              lv_data_type = 'String'.
            WHEN cl_abap_typedescr=>typekind_num OR cl_abap_typedescr=>typekind_packed OR cl_abap_typedescr=>typekind_int OR cl_abap_typedescr=>typekind_float.
              lv_data_type = 'Number'.
            WHEN OTHERS.
              lv_data_type = 'String'.
          ENDCASE.

          o_data = o_doc->create_simple_element( name = 'Data' value = |{ <fs_cell> }| parent = o_cell ).
          o_data->set_attribute_ns( name = 'Type' prefix = 'ss' value = lv_data_type ).
        ENDIF.
      ENDIF.

    ENDLOOP.
  ENDLOOP.

* XML-Dokument rendern
  DATA(o_sf) = o_ixml->create_stream_factory( ).

  DATA: lv_xml TYPE string.

  DATA(o_stream) = o_sf->create_ostream_cstring( lv_xml ).
  o_stream->set_encoding( encoding = o_encoding ).
  o_stream->set_pretty_print( pretty_print = abap_true ).

  DATA(o_render) = o_ixml->create_renderer( ostream  = o_stream
                                            document = o_doc ).

* XML-String in lv_xml generieren
  DATA(lv_rc) = o_render->render( ).

* Dateigröße in Bytes
  DATA(lv_size) = o_stream->get_num_written_raw( ).

* Stream schließen
  o_stream->close( ).

  IF lv_rc = 0 AND lv_size > 0.
* XML-String in XML-Document wandeln
    DATA(o_xml_doc) = NEW cl_xml_document( ).
    o_xml_doc->parse_string( lv_xml ).

* Ausgabe-Datei, "\" müssen quotiert werden
    DATA(lv_fullpath) = |c:\\temp\\test.xml|.

* XML-Document als Datei speichern
    o_xml_doc->export_to_file( CONV #( lv_fullpath ) ).

* lokale Datei im Excel aufrufen
* parameter muss wegen möglicher Leerzeichen im Pfad mit "" quotiert werden
    cl_gui_frontend_services=>execute( application = 'excel.exe'
                                       parameter = |"{ lv_fullpath }"| ).
  ELSE.
    WRITE: / 'Fehler beim Erzeugen der XML-Datei.'.
  ENDIF.

[ABAP] XML-Daten in eine Datei (*.xml) schreiben

Variante 1 (lokal über XML-String)

* ixml Factory
  DATA(o_ixml) = cl_ixml=>create( ).

* Encoding UTF-8
  DATA(o_encoding) = o_ixml->create_encoding( character_set = 'UTF-8'
                                              byte_order = if_ixml_encoding=>co_none ).

* DOM Object Model
  DATA(o_doc) = o_ixml->create_document( ).

  ...

* XML-Dokument rendern
  DATA(o_sf) = o_ixml->create_stream_factory( ).

* XML-String
  DATA: lv_xml TYPE string.

* Stream für Ausgabe in XML-String
  DATA(o_stream) = o_sf->create_ostream_cstring( lv_xml ).
  o_stream->set_encoding( encoding = o_encoding ).
  o_stream->set_pretty_print( pretty_print = abap_true ).

* Render-Objekt
  DATA(o_render) = o_ixml->create_renderer( ostream  = o_stream
                                            document = o_doc ).

* XML-String in lv_xml generieren
  DATA(lv_rc) = o_render->render( ).

* Dateigröße in Bytes
  DATA(lv_size) = o_stream->get_num_written_raw( ).
  
* Stream schließen
  o_stream->close( ).

* Wenn alles ok
  IF lv_rc = 0 AND lv_size > 0.
  * XML-String in XML-Document wandeln
    DATA(o_xml_doc) = NEW cl_xml_document( ).
    o_xml_doc->parse_string( lv_xml ).

  * XML-Document als Datei speichern
    o_xml_doc->export_to_file( 'c:\temp\test.xml' ).
  ENDIF.

Variante 2 (lokal über XML-iTab)

* ixml Factory
  DATA(o_ixml) = cl_ixml=>create( ).

* Encoding UTF-8
  DATA(o_encoding) = o_ixml->create_encoding( character_set = 'UTF-8'
                                              byte_order = if_ixml_encoding=>co_none ).

* DOM Object Model
  DATA(o_doc) = o_ixml->create_document( ).

  ...

* XML-Dokument rendern
  DATA(o_sf) = o_ixml->create_stream_factory( ).

* XML-iTab
  DATA: it_xml_out TYPE STANDARD TABLE OF char255 WITH DEFAULT KEY.

* Encoding UTF-8
  DATA(o_encoding) = o_ixml->create_encoding( character_set = 'UTF-8'
                                              byte_order = if_ixml_encoding=>co_none ).

* Stream für Ausgabe in XML-iTab
  DATA(o_stream) = o_sf->create_ostream_itable( table = it_xml_out ).
  o_stream->set_encoding( encoding = o_encoding ).

* Render-Objekt
  DATA(o_render) = o_ixml->create_renderer( ostream  = o_stream
                                            document = o_doc ).

  o_render->set_normalizing( is_normalizing = space ).

* XML-String in it_xml_out generieren
  DATA(lv_rc) = o_render->render( ).

* Dateigröße in Bytes
  DATA(lv_size) = o_stream->get_num_written_raw( ).
  
* Stream schließen
  o_stream->close( ).

* Wenn alles ok
  IF lv_rc = 0 AND lv_size > 0.
* Tabelle als Binär-Daten herunterladen
    cl_gui_frontend_services=>gui_download( EXPORTING
                                              filename = 'c:\temp\test.xml'
                                              filetype = 'BIN'
                                              bin_filesize = lv_size
                                            CHANGING
                                              data_tab = it_xml_out ).
  ENDIF.

Variante 3 (Applikationsserver)

* ixml Factory
  DATA(o_ixml) = cl_ixml=>create( ).

* DOM Object Model
  DATA(o_doc) = o_ixml->create_document( ).
  
  ...
  
* XML-Dokument rendern
  DATA(o_sf) = o_ixml->create_stream_factory( ).

* Encoding UTF-8
  DATA(o_encoding) = o_ixml->create_encoding( character_set = 'UTF-8'
                                              byte_order = if_ixml_encoding=>co_none ).

* Stream für Ausgabe in Datei '/tmp/test/test.xml' auf dem Applikationsserver
  DATA(o_stream) = o_sf->create_ostream_uri( system_id = '/tmp/test/test.xml' ).
  o_stream->set_encoding( encoding = o_encoding ).
  o_stream->set_pretty_print( pretty_print = abap_true ).

* Render-Objekt
  DATA(o_render) = o_ixml->create_renderer( ostream  = o_stream
                                            document = o_doc ).

* XML-String in Datei auf Applikationsserver generieren
  DATA(lv_rc) = o_render->render( ).

* Dateigröße in Bytes
  DATA(lv_size) = o_stream->get_num_written_raw( ).
  
* Stream schließen
  o_stream->close( ).

* Wenn alles ok
  IF lv_rc = 0 AND lv_size > 0.
    ...
  ENDIF.