[ABAP] XML-Strings parsen

Variante 1 (IF_IXML_ELEMENT, IF_IXML_NODE_COLLECTION)

* 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>| &&
               |  <member name="attr"></member>| &&
               |</object>|.

* XML-Interface
DATA(o_ixml) = cl_ixml=>create( ).
* XML-Doc
DATA(o_doc) = o_ixml->create_document( ).
* Stream-Factory
DATA(o_sf) = o_ixml->create_stream_factory( ).
* Stream
DATA(o_stream) = o_sf->create_istream_string( string = lv_xml ).

* Parser-Objekt erzeugen
DATA(o_parser) = o_ixml->create_parser( document       = o_doc
                                        istream        = o_stream
                                        stream_factory = o_sf ).

* XML parsen
IF o_parser->parse( ) = 0.
* Root-Node
  DATA(o_root) = o_doc->get_root_element( ).

* Alle Nodes mit Namen 'member'
  DATA(o_nodes_member) = o_root->get_elements_by_tag_name( name = 'member' ).
* Iterator für die gefundenen Nodes
  DATA(o_node_iterator_members) = o_nodes_member->create_iterator( ).
* ersten Iterator-Wert holen
  DATA(o_nodes_temp) = o_node_iterator_members->get_next( ).

* Iterator durchgehen
  WHILE NOT o_nodes_temp IS INITIAL.
* Wert der Node ausgeben
    WRITE: / o_nodes_temp->get_value( ).

* Attribute
    DATA(o_note_temp_attr) = o_nodes_temp->get_attributes( ).
    DATA(o_node_temp_item) = o_note_temp_attr->get_named_item( 'name' ).
    IF o_node_temp_item IS BOUND.
      WRITE: / o_node_temp_item->get_value( ).
    ENDIF.

* Children
    DATA(o_node_temp_children) = o_nodes_temp->get_children( ).
    WRITE: / 'Childrens:', o_node_temp_children->get_length( ).

* nächster Iterator-Wert
    o_nodes_temp = o_node_iterator_members->get_next( ).
  ENDWHILE.
ELSE.
* Fehlerauswertung
  DO o_parser->num_errors( ) TIMES.
    DATA(o_err) = o_parser->get_error( index = sy-index - 1 ).
    IF o_err IS BOUND.
      WRITE: / o_err->get_column( ), o_err->get_line( ), o_err->get_reason( ).
    ENDIF.
  ENDDO.
ENDIF.

Variante 2 (find_from_name)

* 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>| &&
               |  <member name="attr"></member>| &&
               |</object>|.

* XML-Interface
DATA(o_ixml) = cl_ixml=>create( ).
* XML-Doc
DATA(o_doc) = o_ixml->create_document( ).
* Stream-Factory
DATA(o_sf) = o_ixml->create_stream_factory( ).
* Stream
DATA(o_stream) = o_sf->create_istream_string( string = lv_xml ).

* Parser-Objekt erzeugen
DATA(o_parser) = o_ixml->create_parser( document       = o_doc
                                        istream        = o_stream
                                        stream_factory = o_sf ).

* XML parsen
IF o_parser->parse( ) = 0.
* <object>
  DATA(o_root) = o_doc->find_from_name( 'object' ).

  IF o_root IS BOUND.
* <str ...>
    DATA(o_str) = o_root->get_first_child( ).
    IF o_str IS BOUND.
* Wert der Node ausgeben
      WRITE: / o_str->get_value( ).

* Attribut 'name'
      DATA(o_attr) = o_str->get_attributes( ).
      DATA(o_name) = o_attr->get_named_item( 'name' ).
      IF o_name IS BOUND.
        WRITE: / o_name->get_value( ).
      ENDIF.
    ENDIF.
  ENDIF.
ELSE.
* Fehlerauswertung
  DO o_parser->num_errors( ) TIMES.
    DATA(o_err) = o_parser->get_error( index = sy-index - 1 ).
    IF o_err IS BOUND.
      WRITE: / o_err->get_column( ), o_err->get_line( ), o_err->get_reason( ).
    ENDIF.
  ENDDO.
ENDIF.

[ABAP] SALV-Tree: Beispiel für Verwendung von cl_salv_tree

* Demoprogramme
*
* SALV_DEMO_TREE_DATA_UPDATE
* SALV_DEMO_TREE_EVENTS
* SALV_DEMO_TREE_FUNCTIONS
* SALV_DEMO_TREE_METADATA
* SALV_DEMO_TREE_SELECTIONS
* SALV_DEMO_TREE_SETTINGS
* SALV_DEMO_TREE_SIMPLE

TYPES: ty_it_spfli TYPE STANDARD TABLE OF spfli WITH DEFAULT KEY.

DATA: o_tree TYPE REF TO cl_salv_tree.
DATA: it_spfli TYPE ty_it_spfli.
DATA: it_spfli_empty TYPE ty_it_spfli.

* Eventhandlerklasse
CLASS lcl_events DEFINITION.
  PUBLIC SECTION.

    CLASS-METHODS:
      on_button_click FOR EVENT link_click OF cl_salv_events_tree
        IMPORTING
            columnname
            node_key
            sender.
    CLASS-METHODS:
      on_user_command FOR EVENT added_function OF cl_salv_events
        IMPORTING
            e_salv_function
            sender.
ENDCLASS.

CLASS lcl_events IMPLEMENTATION.

  METHOD on_button_click.

    TRY.
        IF o_tree IS BOUND.
* Unternode (Child) zur akt. geklickten Node holen
          DATA(o_child_node) = o_tree->get_nodes( )->get_node( node_key )->get_first_child( ).

* alle Unternodes durchlaufen und Checkbox der Spalte Carrier setzen
          WHILE o_child_node IS BOUND.

            DATA(o_item) = o_child_node->get_item( 'CARRID' ).

            IF o_item->is_checked( ) = abap_true.
              o_item->set_checked( abap_false ).
            ELSE.
              o_item->set_checked( abap_true ).
            ENDIF.

            o_child_node = o_child_node->get_next_sibling( ).
          ENDWHILE.

        ENDIF.
      CATCH cx_salv_msg.
    ENDTRY.

  ENDMETHOD.

  METHOD on_user_command.
    MESSAGE e_salv_function TYPE 'I'.
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.
* Daten holen
  SELECT * FROM spfli INTO CORRESPONDING FIELDS OF TABLE it_spfli.

  SORT: it_spfli BY carrid.

  TRY.
* Tree-Objekt mit leerer Tabelle (Dummy) erzeugen
      cl_salv_tree=>factory( IMPORTING
                               r_salv_tree = o_tree
                             CHANGING
                               t_table     = it_spfli_empty ).

* Header setzen
      o_tree->get_tree_settings( )->set_header( CONV #( sy-title ) ).
      o_tree->get_tree_settings( )->set_hierarchy_header( 'Carrier' ).
      o_tree->get_tree_settings( )->set_hierarchy_tooltip( 'Carrier' ).
      o_tree->get_tree_settings( )->set_hierarchy_size( 40 ).
      o_tree->get_tree_settings( )->set_hierarchy_icon( CONV #( icon_tree ) ).

* Treenodes einfügen
      LOOP AT it_spfli ASSIGNING FIELD-SYMBOL(<c>) GROUP BY <c>-carrid.

        DATA(it_cp) = VALUE ty_it_spfli( FOR <cp> IN GROUP <c> ( <cp> ) ).

        DATA(o_parent) = o_tree->get_nodes( )->add_node( related_node   = ''
                                                         relationship   = cl_gui_column_tree=>relat_last_child
                                                         collapsed_icon = CONV #( icon_closed_folder )
                                                         expanded_icon  = CONV #( icon_open_folder )
                                                         row_style      = if_salv_c_tree_style=>intensified
                                                         text           = CONV #( <c>-carrid ) ).

        IF lines( it_cp ) > 1.
          o_parent->get_item( 'CARRID' )->set_type( if_salv_c_item_type=>button ).
          o_parent->get_item( 'CARRID' )->set_value( 'all' ).
        ENDIF.

        LOOP AT GROUP <c> ASSIGNING FIELD-SYMBOL(<f>).
          DATA(o_carrid) = o_tree->get_nodes( )->add_node( related_node = o_parent->get_key( )
                                                           relationship = cl_gui_column_tree=>relat_last_child
                                                           data_row     = <f>
                                                           row_style    = if_salv_c_tree_style=>intensified
                                                           text         = CONV #( <f>-connid ) ).

          o_carrid->get_item( 'CARRID' )->set_type( if_salv_c_item_type=>checkbox ).
          o_carrid->get_item( 'CARRID' )->set_editable( abap_true ).
        ENDLOOP.

      ENDLOOP.

* Mandant ausblenden
      o_tree->get_columns( )->get_column( 'MANDT' )->set_technical( abap_true ).
* Carrid zentriert
      o_tree->get_columns( )->get_column( 'CARRID' )->set_alignment( if_salv_c_alignment=>right ).

* Spaltenbreiten optimieren
      o_tree->get_columns( )->set_optimize( abap_true ).

* Flugzeiten Aggregieren
      o_tree->get_aggregations( )->add_aggregation( columnname  = 'FLTIME'
                                                    aggregation = if_salv_c_aggregation=>total ).

* Alle Funktionsbuttons einschalten
      o_tree->get_functions( )->set_all( abap_true ).

* eigenen Button hinzufügen
* das Hinzufügen des Buttons funktioniert nur, wenn die SALV-Table innerhalb eines Containers (z.B. cl_gui_container=>default_screen) eingebettet ist
*      o_tree->get_functions( )->add_function( name     = 'BTN_USR'
*                                              icon     = CONV #( icon_abap )
*                                              text     = 'Testbutton'
*                                              tooltip  = 'Testbutton'
*                                              position = if_salv_c_function_position=>right_of_salv_functions ).

* Handler für Button-Click setzen
      SET HANDLER lcl_events=>on_button_click FOR o_tree->get_event( ).
*      SET HANDLER lcl_events=>on_user_command FOR o_tree->get_event( ).

      o_tree->display( ).
    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.