[ABAP] RTTI / RTTC / RTTS: Verwendung von Typdescriptoren

* Typ-Beispiele:
* Struct
*   RSDSSELOPT
* Table
*   RSELOPTION
* Klasse
*   CL_DEMO_OUTPUT
* Interface
*   IF_RANDOM_NUMBER
* Datenelement
*   I
* Referenz
*   ?
PARAMETERS: p_name TYPE string DEFAULT 'RSDSSELOPT'.

START-OF-SELECTION.

  DATA(o_type_desc) = cl_abap_typedescr=>describe_by_name( p_name ).

  CASE o_type_desc->kind.
    WHEN cl_abap_typedescr=>kind_struct.
      DATA(o_struct_desc) = CAST cl_abap_structdescr( o_type_desc ).
      cl_demo_output=>write_data( o_struct_desc->components ).
    WHEN cl_abap_typedescr=>kind_table.
      DATA(o_table_desc) = CAST cl_abap_tabledescr( o_type_desc ).
      DATA(o_tl_struct_desc) = CAST cl_abap_structdescr( o_table_desc->get_table_line_type( ) ).
      cl_demo_output=>write_data( o_tl_struct_desc->components ).
    WHEN cl_abap_typedescr=>kind_class.
      DATA(o_class_desc) = CAST cl_abap_classdescr( o_type_desc ).
      LOOP AT o_class_desc->methods ASSIGNING FIELD-SYMBOL(<m>).
        cl_demo_output=>write( <m>-name ).
      ENDLOOP.
    WHEN cl_abap_typedescr=>kind_intf.
      DATA(o_if_desc) = CAST cl_abap_intfdescr( o_type_desc ).
      LOOP AT o_if_desc->methods ASSIGNING FIELD-SYMBOL(<i>).
        cl_demo_output=>write( <i>-name ).
      ENDLOOP.
    WHEN cl_abap_typedescr=>kind_elem.
      DATA(o_elem_desc) = CAST cl_abap_elemdescr( o_type_desc ).
      cl_demo_output=>write_data( o_elem_desc->type_kind ).
    WHEN cl_abap_typedescr=>kind_ref.
  ENDCASE.

  cl_demo_output=>display( ).

Links

[ABAP] IDoc: Strukturen der IDoc-Segmente in eine interne Tabelle lesen

* http://thinkdoforward.com/sap-idoc-tabellen-erfahrene-berater-kennen-diese-tabellen/

* Tabellen: EDIDC   – Kontrollsatz (IDoc)
*           EDIDS   – Statussatz (IDoc)
*           EDID4   – IDoc-Datensätze ab 4.0
*           EDISDEF - IDoc Entwicklung : IDoc Segmentdefinitionen
*           EDSAPPL - EDI: IDoc-Segment Anwendungsstruktur
*           EDIMSGT - Kurzbeschreibung der SAP Nachrichtentypen

TYPES: BEGIN OF ty_idoc_seg_entry,
         seg_name  TYPE string,
         comp_name TYPE string,
         value     TYPE string,
       END OF ty_idoc_seg_entry.

* IDoc-Nummer
PARAMETERS: p_idoc TYPE edidc-docnum DEFAULT '12345'.

START-OF-SELECTION.

* Lesen Segmentdaten des IDocs
  SELECT *
    INTO TABLE @DATA(it_int_edid)
    FROM edid4
    WHERE docnum EQ @p_idoc.

  IF sy-subrc = 0.
* Tabelle für aufbereitete Segmentdaten
    DATA: it_segment_data TYPE STANDARD TABLE OF ty_idoc_seg_entry WITH DEFAULT KEY.

* all. Feldsymbol für Umwandlung der Daten
    FIELD-SYMBOLS: <seg_data> TYPE any.

* Segmentdaten auslesen
    LOOP AT it_int_edid ASSIGNING FIELD-SYMBOL(<s>).
* Typecast für Umwandlung LCHR -> Type
      ASSIGN <s>-sdata TO <seg_data> CASTING TYPE (<s>-segnam).

* Typedescriptor zum Auslesen der einzelnen Datenfelder
      DATA(o_type) = cl_abap_typedescr=>describe_by_data( <seg_data> ).

      CASE o_type->kind.
* wenn Strukturtyp
        WHEN cl_abap_typedescr=>kind_struct.
          DATA(o_desc) = CAST cl_abap_structdescr( o_type ).

* Datenfelder der Struktur durchloopen
          LOOP AT o_desc->get_components( ) ASSIGNING FIELD-SYMBOL(<c>).
* Wert des Feldes auslesen
            ASSIGN COMPONENT <c>-name OF STRUCTURE <seg_data> TO FIELD-SYMBOL(<val>).
            IF <val> IS ASSIGNED.
* Zeile für Segment erstellen mit Segmentname, Komponenten-(Feld-)name, Wert
              APPEND VALUE #( seg_name  = <s>-segnam
                              comp_name = <c>-name
                              value     = <val>
                            ) TO it_segment_data.
            ENDIF.
          ENDLOOP.

        WHEN OTHERS.

      ENDCASE.
    ENDLOOP.

* Datenausgabe
    cl_demo_output=>display( it_segment_data ).
  ENDIF.

[ABAP] Globale Objekte eines Programms ermitteln und Infos anzeigen

Variante 1 (lokale Infoklasse)

* Quellen: https://blogs.sap.com/2018/08/27/sapgui-is-dying-but-still-secrets-to-reveal.../
*          https://github.com/tricktresor/container_hierarchy

CLASS lcl_global_symbols DEFINITION.
  PUBLIC SECTION.
    TYPES: BEGIN OF ty_obj_info,
             name          TYPE rfieldlist-name,
             type          TYPE rfieldlist-type,
             reftypeloc    TYPE rfieldlist-reftypeloc,
             global_name   TYPE string,
             relative_name TYPE string,
             object_name   TYPE string,
             object_id     TYPE i,
             reference     TYPE REF TO object,
             error         TYPE string,
           END OF ty_obj_info.

    TYPES: ty_it_obj_info TYPE STANDARD TABLE OF ty_obj_info WITH DEFAULT KEY.

    CONSTANTS: null TYPE REF TO object VALUE IS INITIAL.

    CLASS-METHODS:
      get_obj_info
        IMPORTING
                  iv_name               TYPE rfieldlist-name
                  iv_type               TYPE rfieldlist-type DEFAULT 'r'
                  iv_reftypeloc         TYPE rfieldlist-reftypeloc DEFAULT 'CLAS'
        RETURNING VALUE(rv_it_obj_info) TYPE ty_it_obj_info.
ENDCLASS.

CLASS lcl_global_symbols IMPLEMENTATION.
  METHOD get_obj_info.
    DATA: it_fieldlist TYPE STANDARD TABLE OF rfieldlist WITH DEFAULT KEY.
* Liste der globalen Daten eines Programms
    CALL FUNCTION 'GET_GLOBAL_SYMBOLS'
      EXPORTING
        program      = sy-repid
        name_pattern = '*'
      TABLES
        fieldlist    = it_fieldlist.

    DATA(lv_where) = ||.

    IF NOT iv_name IS INITIAL.
      lv_where = |name CP iv_name AND type = iv_type AND reftypeloc = iv_reftypeloc|.
    ENDIF.

    LOOP AT it_fieldlist ASSIGNING FIELD-SYMBOL(<f>) WHERE (lv_where).

      DATA(lv_global_name) = |({ sy-repid }){ <f>-name }|.
      DATA(lv_relative_name) = ||.
      DATA(lv_object_name) = ||.
      DATA(lv_error) = ||.
      DATA: lv_oid TYPE i.

* Wenn Referenztyp
      IF <f>-type = 'r'.
* Dirty Assign: Namen an Feldsymbol vom TYPE ANY binden
        ASSIGN (lv_global_name) TO FIELD-SYMBOL(<o>).

        IF NOT <o> IS INITIAL.
          IF <o> IS ASSIGNED.
            TRY.
* <o> ist eine Referenz
                IF <o> IS BOUND.
* Descriptor für Objektreferenz
                  DATA(o_desc) = cl_abap_typedescr=>describe_by_object_ref( <o> ).

                  lv_relative_name = o_desc->get_relative_name( ).

* ObjektID zur Referenz ermitteln
                  CALL 'OBJMGR_GET_INFO' ID 'OPNAME' FIELD 'GET_OBJID'
                                         ID 'OBJID'  FIELD lv_oid      " Rückgabe: ObjectID
                                         ID 'OBJ'    FIELD <o>.

                  lv_object_name = |\{O:{ lv_oid }*{ o_desc->absolute_name }|.
                ENDIF.
              CATCH cx_root INTO DATA(e_txt).
                lv_error = e_txt->get_text( ).
            ENDTRY.
          ENDIF.
        ENDIF.
      ENDIF.

      APPEND VALUE #(
                      name          = <f>-name
                      type          = <f>-type
                      reftypeloc    = <f>-reftypeloc
                      global_name   = lv_global_name
                      relative_name = lv_relative_name
                      object_name   = lv_object_name
                      object_id     = lv_oid
                      reference     = COND #( WHEN ( <o> IS ASSIGNED AND NOT <o> IS INITIAL ) THEN <o> ELSE null )
                      error         = lv_error
                    ) TO rv_it_obj_info.
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

DATA: o_dock TYPE REF TO cl_gui_docking_container.
DATA: o_text TYPE REF TO cl_gui_textedit.

PARAMETERS: p_matnr TYPE mara-matnr.

INITIALIZATION.

  IF NOT o_dock IS BOUND.
* GUI-Objekte für Test erzeugen
    o_dock = NEW #( side  = cl_gui_docking_container=>dock_at_bottom
                    ratio = 90 ).

    o_text = NEW #( parent = o_dock ).
  ENDIF.

START-OF-SELECTION.

* Infos zu 'o_dock' holen
  DATA(it_one) = lcl_global_symbols=>get_obj_info( iv_name = 'o_dock' ).

  LOOP AT it_one ASSIGNING FIELD-SYMBOL(<one>).

    DATA(lv_ref_one) = ||.

    IF <one>-reference IS BOUND.
      lv_ref_one = <one>-object_name.
    ENDIF.

    WRITE: / <one>-name, <one>-type, <one>-reftypeloc, <one>-global_name, <one>-relative_name, <one>-object_name, <one>-object_id, lv_ref_one, <one>-error.
  ENDLOOP.

  ULINE.

* Infos zu allen Objekten holen
  DATA(it_all) = lcl_global_symbols=>get_obj_info( iv_name = '' ).

  LOOP AT it_all ASSIGNING FIELD-SYMBOL(<o>).

    DATA(lv_ref) = ||.

    IF <o>-reference IS BOUND.
      lv_ref = <o>-object_name.
    ENDIF.

    WRITE: / <o>-name, <o>-type, <o>-reftypeloc, <o>-global_name, <o>-relative_name, <o>-object_name, <o>-object_id, lv_ref, <o>-error.
  ENDLOOP.

Variante 2 (Container)

DATA: o_dock TYPE REF TO cl_gui_docking_container.
DATA: o_text TYPE REF TO cl_gui_textedit.

DATA: it_fieldlist TYPE STANDARD TABLE OF rfieldlist WITH DEFAULT KEY.

PARAMETERS: p_matnr TYPE mara-matnr.

INITIALIZATION.

  IF NOT o_dock IS BOUND.
* GUI-Objekte für Test erzeugen
    o_dock = NEW #( side  = cl_gui_docking_container=>dock_at_bottom
                    ratio = 90 ).

    o_text = NEW #( parent = o_dock ).
  ENDIF.

AT SELECTION-SCREEN.
* Liste der globalen Daten eines Programms
  CALL FUNCTION 'GET_GLOBAL_SYMBOLS'
    EXPORTING
      program      = sy-repid
      name_pattern = '*'
    TABLES
      fieldlist    = it_fieldlist.

START-OF-SELECTION.
* globalen Daten nach Referenztypen durchloopen
  LOOP AT it_fieldlist ASSIGNING FIELD-SYMBOL(<f>) WHERE type = 'r' AND reftypeloc = 'CLAS' AND name(1) <> '%'.

    WRITE: / '         name:', <f>-name.

* Globalen Namen des Objekts ermitteln
    DATA(lv_global_name) = |({ sy-repid }){ <f>-name }|.
    WRITE: / '  global name:', lv_global_name.

* Dirty Assign: Namen an Feldsymbol vom TYPE ANY binden
    ASSIGN (lv_global_name) TO FIELD-SYMBOL(<o>).
    IF <o> IS ASSIGNED.
      TRY.
* <o> ist eine Referenz
          IF <o> IS BOUND.
* Descriptor für Objektreferenz
            DATA(o_desc) = cl_abap_typedescr=>describe_by_object_ref( <o> ).

            WRITE: / 'relative name:', o_desc->get_relative_name( ).

            DATA: lv_oid TYPE i.

* ObjektID zur Referenz ermitteln
            CALL 'OBJMGR_GET_INFO' ID 'OPNAME' FIELD 'GET_OBJID'
                                   ID 'OBJID'  FIELD lv_oid      " Rückgabe: ObjectID
                                   ID 'OBJ'    FIELD <o>.

            WRITE: / '  object name:', |\{O:{ lv_oid }*{ o_desc->absolute_name }|.

* Gegenprobe
            DATA: o_ref_weak TYPE REF TO object.

* Referenz zur ObjektID ermitteln
            CALL 'OBJMGR_GET_INFO' ID 'OPNAME' FIELD 'WEAK_REF_GET'
                                   ID 'OID'    FIELD lv_oid
                                   ID 'OBJ'    FIELD o_ref_weak. " Rückgabe: Objekt-Referenz

            IF o_ref_weak IS BOUND.
* Descriptor für Objektreferenz
              DATA(o_desc_weak) = cl_abap_typedescr=>describe_by_object_ref( o_ref_weak ).
              WRITE: / 'relative name weak:', o_desc_weak->get_relative_name( ).
              WRITE: / '  object name weak:', |\{O:{ lv_oid }*{ o_desc_weak->absolute_name }|.
            ENDIF.

* Falls cl_gui_container: Children anzeigen
            TRY.
                DATA(o_cont) = CAST cl_gui_container( <o> ).

                LOOP AT o_cont->children ASSIGNING FIELD-SYMBOL(<child>).
                  DATA(o_desc_child) = cl_abap_typedescr=>describe_by_object_ref( <child> ).
                  WRITE: / ' --> child relative name:', o_desc_child->get_relative_name( ).
                ENDLOOP.
              CATCH cx_root.
            ENDTRY.
          ELSE.
            WRITE: 'keine Referenz verfügbar.'.
          ENDIF.

        CATCH cx_root INTO DATA(e_txt).
          WRITE: / e_txt->get_text( ).
      ENDTRY.
    ELSE.
      WRITE: 'Feldsymbol nicht zugewiesen:', lv_global_name.
    ENDIF.

    ULINE.
  ENDLOOP.

[ABAP] Abbildung von boolschen Werten im ABAP

Typen

Typ          Herkunft                  Anmerkung
----------------------------------------------------------------------------------------------------------------------------------
abap_bool    Typegruppe ABAP           empfohlen in den offiziellen ABAP Programming Guidelines
                                       Ab Release 7.40 sind bei Predicative Method Calls Rückgabewerte vom Typ ABAP_BOOL notwendig
                                       https://help.sap.com/doc/abapdocu_752_index_htm/7.52/de-DE/abenpredicative_method_calls.htm
boolean      Datenelement BOOLEAN      hat keine Feldbezeichner
xfeld        Datenelement XFELD        hat keine Feldbezeichner
os_boolean   Datenelement OS_BOOLEAN
wdy_boolean  Datenelement WDY_BOOLEAN
ddbool_d     Datenelement DDBOOL_D

Werte

boolscher Typ  ABAP-Konstante                ABAP-Wert  Definition         Datentyp  Länge
------------------------------------------------------------------------------------------
true           abap_true                     'X'        Typegruppe ABAP    char      1
false          abap_false                    ' '        Typegruppe ABAP    char      1
               abap_undefined                '-'        Typegruppe ABAP    char      1
true           cl_abap_typedescr=>true       'X'        cl_abap_typedescr  char      1
false          cl_abap_typedescr=>false      ' '        cl_abap_typedescr  char      1
               cl_abap_typedescr=>undefined  '-'        cl_abap_typedescr  char      1

[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] Wertebereich einer Domäne auslesen

Variante 1 (get_ddic_fixed_values)

CLASS lcl_domvalues DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS: get_by_type
      IMPORTING
                iv_data               TYPE any
      RETURNING VALUE(rt_ddfixvalues) TYPE ddfixvalues.
    CLASS-METHODS: get_by_name
      IMPORTING
                iv_name               TYPE domname
      RETURNING VALUE(rt_ddfixvalues) TYPE ddfixvalues.
ENDCLASS.

CLASS lcl_domvalues IMPLEMENTATION.

  METHOD get_by_type.
    TRY.
* liefert Typebeschreibung für DDIC-Typ
        rt_ddfixvalues = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( iv_data ) )->get_ddic_fixed_values( ).
      CATCH cx_root.
    ENDTRY.
  ENDMETHOD.

  METHOD get_by_name.
    TRY.
* liefert Typebeschreibung für DDIC-Typ
        rt_ddfixvalues = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_name( iv_name ) )->get_ddic_fixed_values( ).
      CATCH cx_root.
    ENDTRY.
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

* Domäne über Variablen-Typ
  DATA(lv_cat) = VALUE cccategory( ).
  DATA(it_by_type) = lcl_domvalues=>get_by_type( lv_cat ).

* Domäne über Name
  DATA(it_by_name) = lcl_domvalues=>get_by_name( 'CCCATEGORY' ).

  cl_demo_output=>write_data( it_by_type ).
  cl_demo_output=>write_data( it_by_name ).

  cl_demo_output=>display( ).

Variante 2 (DD_DOMVALUES_GET)

DATA(it_dd07v_tab) = VALUE dd07v_tab( ).
DATA(lv_rc) = VALUE sy-subrc( ).

CALL FUNCTION 'DD_DOMVALUES_GET'
  EXPORTING
    domname        = 'CCCATEGORY'
    text           = abap_true
*   LANGU          = ' '
*   BYPASS_BUFFER  = ' '
  IMPORTING
    rc             = lv_rc
  TABLES
    dd07v_tab      = it_dd07v_tab
  EXCEPTIONS
    wrong_textflag = 1
    OTHERS         = 2.

IF sy-subrc = 0.
  IF lv_rc = 0.
    cl_demo_output=>display( it_dd07v_tab ).
  ENDIF.
ENDIF.

Variante 3 (SQL)

* Name der Domäne
DATA(lv_domain) = 'CCCATEGORY'.
* Anmeldesprache
DATA(lv_lang) = cl_abap_syst=>get_logon_language( ).

SELECT l~domvalue_l, t~ddtext
  INTO TABLE @DATA(it_dom)
  FROM dd07l AS l
  INNER JOIN dd07t AS t ON l~domname = t~domname AND l~valpos = t~valpos AND l~domvalue_l = t~domvalue_l
  WHERE l~domname    = @lv_domain
    AND t~ddlanguage = @lv_lang.

cl_demo_output=>display( it_dom ).

Variante 4 (cl_reca_ddic_doma)

DATA(it_rsdomaval) = VALUE re_t_rsdomaval( ).

* DDIC-Objekt: Domäne
cl_reca_ddic_doma=>get_values( EXPORTING id_name   = 'CCCATEGORY'
                               IMPORTING et_values = it_rsdomaval ).

cl_demo_output=>display( it_rsdomaval ).

Variante 5 (cl_reca_ddic_doma)

DATA(lv_dd01v) = VALUE dd01v( ).
DATA(it_rsdomaval) = VALUE re_t_rsdomaval( ).

* DDIC-Objekt: Domäne
cl_reca_ddic_doma=>get_complete( EXPORTING id_name      = 'CCCATEGORY'
                                 IMPORTING es_header    = lv_dd01v
                                           et_rsdomaval = it_rsdomaval ).

cl_demo_output=>write_data( lv_dd01v ).
cl_demo_output=>write_data( it_rsdomaval ).
cl_demo_output=>display( ).

[ABAP] Generische Verarbeitung von internen Tabellen / Verwendung von Referenzen

* irgendeine interne Tablelle anlegen
DATA: it_tab TYPE STANDARD TABLE OF ...
* generische Tabellenreferenz anlegen
DATA: o_ref_table TYPE REF TO data.
 
...
 
* Tabellenreferenz übergeben
o_ref_table = REF #( it_tab ).
 
* Referenz auf generisches Feldsymbol mappen
FIELD-SYMBOLS: <tab> TYPE ANY TABLE.
ASSIGN o_ref_table->* TO <tab>.
 
* Tabellen-Zeile erzeugen
* muss hier erfolgen, damit man ein "greifbares" Tabellen-Zeilen-Objekt
* für die Strukturermittlung (describe_by_data) hat
DATA: o_row TYPE REF TO data.
CREATE DATA o_row LIKE LINE OF <tab>.
FIELD-SYMBOLS: <row> TYPE any.
ASSIGN o_row->* TO <row>.
 
* Komponenten (Spalten) einer Tabellenzeile ermitteln
DATA(o_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( <row> ) ).
DATA(it_comp_tab) = o_struct->get_components( ).
 
* Anzahl Spalten der Tabellen-Zeile holen
DATA(lv_colcnt) = lines( it_comp_tab ).
 
* Tabelle durchloopen
LOOP AT <tab> ASSIGNING <row>.

* Spalten der akt. Zeile durchgehen
  DO lv_colcnt TIMES.
* Zelle: n-tes Element der akt. Zeile holen
    ASSIGN COMPONENT sy-index OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
    
* Trennzeichen vor die Spalte einfügen, wenn nicht 1. Spalte
    IF sy-index > 1.
      WRITE: '|'.
    ENDIF.

* Achtung: Zell-Typ beachten! Es können hier nur flache Typen (Keine Strukturen, Tabellen) ausgegeben werden, der Rest muss gesondert behandelt werden
    IF CAST cl_abap_elemdescr( it_comp_tab[ sy-index ]-type )->kind = cl_abap_elemdescr=>kind_elem.
* Ausgabe Zellinhalt mit vordefinierter Spaltenbreite
      WRITE: |{ <cell> WIDTH = 20 |.
    ENDIF.
  ENDDO.

  NEW-LINE.
ENDLOOP.

[ABAP] Dynamische Tabelle anhand eines Tabellennamens erstellen, Daten ausgeben

DATA: table_name TYPE string VALUE 'spfli'. " Tabellenname
DATA: o_it TYPE REF TO data.                " Referenz auf Tabelle
DATA: o_row TYPE REF TO data.               " Referenz auf Tabellenzeile

FIELD-SYMBOLS: <fs_table> TYPE ANY TABLE.   " Feldsymbol für Arbeit mit Tabelle
FIELD-SYMBOLS: <fs_row> TYPE any.           " Feldsymbol für Arbeit mit Zeile

* dynamische Tabelle vom Typ table_name erzeugen
CREATE DATA o_it TYPE TABLE OF (table_name).
* Feldsymbol auf die dynamische Tabelle anlegen
ASSIGN o_it->* TO <fs_table>.

IF <fs_table> IS ASSIGNED.
* dynamische Workarea vom Typ der Tabellenzeile erzeugen
  CREATE DATA o_row LIKE LINE OF <fs_table>.
* Feldsymbol auf die Workarea anlegen
  ASSIGN o_row->* TO <fs_row>.

  IF <fs_row> IS ASSIGNED.
* Daten holen
    SELECT * FROM (table_name) INTO TABLE <fs_table>.

* Daten ausgeben
    DATA: go_struct TYPE REF TO cl_abap_structdescr.

* herausfinden, wieviele Spalten die Tabelle hat
    go_struct ?= cl_abap_typedescr=>describe_by_data( <fs_row> ).
    DATA(gt_comp) = go_struct->get_components( ).

* alle Datensätze der Tabelle durchgehen
    LOOP AT <fs_table> INTO <fs_row>.

* spaltenweise jeden Datensatz durchgehen
      LOOP AT gt_comp ASSIGNING FIELD-SYMBOL(<fs_col>).
* den Inhalt der Strukturkomponente (Zeile) ausgeben
        ASSIGN COMPONENT <fs_col>-name OF STRUCTURE <fs_row> TO FIELD-SYMBOL(<fs_cell>).

        IF <fs_cell> IS ASSIGNED.
          WRITE: <fs_cell>.
        ENDIF.
      ENDLOOP.

      NEW-LINE.

    ENDLOOP.
  ENDIF.
ENDIF.

[ABAP] SALV-Table – technische Namen der Spalten anzeigen

Variante 1 (kurz)

DATA: o_salv TYPE REF TO cl_salv_table.

...

LOOP AT o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
  <c>-r_column->set_short_text( |{ <c>-r_column->get_columnname( ) }| ).
  <c>-r_column->set_medium_text( |{ <c>-r_column->get_columnname( ) }| ).
  <c>-r_column->set_long_text( |{ <c>-r_column->get_columnname( ) }| ).
ENDLOOP.

Variante 2 (RTTS, RTTI)

DATA: o_alv TYPE REF TO cl_salv_table.

...

* Datendescriptor für Tabellenzeile (z.B.: Struct "ls_spfli") holen
DATA: o_struct TYPE REF TO cl_abap_structdescr.
o_struct ?= cl_abap_typedescr=>describe_by_data( ls_spfli ).

DATA: o_comp_tab TYPE abap_component_tab.
o_comp_tab = o_struct->get_components( ).

* Spalten der SALV-Table holen
DATA(lo_columns) = o_salv->get_columns( ).
DATA: lv_col TYPE REF TO cl_salv_column.
            
LOOP AT o_comp_tab INTO DATA(ls_comp).
  lv_col ?= lo_columns->get_column( |{ ls_comp-name }| ).

* Spaltennamen auf Structnamen ändern
  lv_col->set_short_text( | { ls_comp-name } | ).
  lv_col->set_medium_text( | { ls_comp-name } | ).
  lv_col->set_long_text( | { ls_comp-name } | ).
ENDLOOP.