[ABAP] ABAP-Proxy-Objekt in XML wandeln und anzeigen

Variante 1 (ABAP_TO_XML_XSTRING)

TRY.
* Proxyobjekt
    DATA(lv_proxy_obj) = VALUE zgenerated_proxy_obj( p_par1 = 'VALUE1'
                                                     p_par2 = 'VALUE2'
                                                   ).

* Proxy-Objekt
    DATA(lv_datatype) = CONV prx_r3name( 'ZGENERATED_PROXY_OBJ' ).

* Simple Transformation mit Namespace
* xml_header
* no
* without_encoding
* full
    DATA(lv_xml) = cl_proxy_xml_transform=>abap_to_xml_xstring( abap_data  = lv_proxy_obj
                                                                ddic_type  = lv_datatype
                                                                xml_header = 'full' " no, without_encoding, full
                                                              ).

* Transformation
    CALL TRANSFORMATION id SOURCE XML lv_xml RESULT XML lv_xml.

* XML anzeigen
    cl_srtg_helper=>write_utf8_xmldoc( doc              = lv_xml
                                       use_html_control = abap_true " Anzeige im Browserfenster
                                     ).

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

Variante 2 (CL_SXML_STRING_WRITER)

TRY.
* Proxyobjekt
    DATA(lv_proxy_obj) = VALUE zgenerated_proxy_obj( p_par1 = 'VALUE1'
                                                     p_par2 = 'VALUE2'
                                                   ).

* Proxy-Objekt
    DATA(lv_datatype) = CONV prx_r3name( 'ZGENERATED_PROXY_OBJ' ).

    DATA(o_xml_writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 ).

* Simple Transformation mit Namespace
    cl_proxy_xml_transform=>abap_to_xml( abap_data  = lv_proxy_obj
                                         ddic_type  = lv_datatype
                                         xml_writer = o_xml_writer
                                       ).

    DATA(lv_xml) = o_xml_writer->get_output( ).

* Transformation
    CALL TRANSFORMATION id SOURCE XML lv_xml RESULT XML lv_xml.

* XML anzeigen
    cl_srtg_helper=>write_utf8_xmldoc( doc              = lv_xml
                                       use_html_control = abap_true " Anzeige im Browserfenster
                                     ).

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

[ABAP] RegEx: Strings ersetzen

* Platzhalter: Zeichenkette, die ersetzt werden soll
DATA(lv_placeholder) = |<placeholder>|.
* Replacement: Zeichenkette, die anstelle des Platzhalters eingesetzt wird
DATA(lv_replacement) = | und |.

* Alle Vorkommen des Platzhalters im String finden
DATA(matcher) = cl_abap_matcher=>create( pattern     = lv_placeholder
                                         text        = 'Ich fahre gerne Auto<placeholder>Fahrrad<placeholder>Straßenbahn.'
                                         ignore_case = abap_true ).

* Alle Platzhalter mit Replacement ersetzen
IF matcher->replace_all( lv_replacement ) > 0.
  WRITE: / matcher->text.
ELSE.
  WRITE: / |Zeichenkette '{ lv_placeholder }' nicht im String vorhanden.|.
ENDIF.

[ABAP] RegEx: HTML-Tags aus String entfernen

* HTML
DATA(lv_html) = |<!DOCTYPE html>| &&
                |<html>| &&
                |<head>| &&
                |  <meta charset="utf-8">| &&
                |  <meta name="viewport" content="width=device-width">| &&
                |  <title>DOM Read</title>| &&
                |</head>| &&
                |<body>| &&
                |  <div id="bodytext"><b>Hallo Welt!</b></div>| &&
                |  <div id="bodytext">Weiterlesen: <a href="https://codezentrale.de">Link</a></div>| &&
                |</body>| &&
                |</html>|.

* Alle HTML-Tags finden
DATA(matcher) = cl_abap_matcher=>create( pattern     = '<([!A-Za-z][A-Za-z0-9]*)([^>]*)>|</([A-Za-z][A-Za-z0-9]*)>'
                                         text        = lv_html
                                         ignore_case = abap_true ).

* Alle gefundenen HTML-Tags mit '' ersetzen
IF matcher->replace_all( '' ) > 0.
  WRITE: / matcher->text.
ELSE.
  WRITE: / |Keine Tags gefunden.|.
ENDIF.

[ABAP] RegEx: Submatches in einem String finden

Variante 1 (cl_abap_matcher)

* mehrere Submatches in einer vorgegebenen Ordnerstruktur finden
* Unterordner mit '/<Zahlen>'
DATA(matcher) = cl_abap_matcher=>create( pattern     = '/([0-9]{1,5})'
                                         text        = '/category/12345/item/12'
                                         ignore_case = abap_true ).

WHILE abap_true = matcher->find_next( ).
  WRITE: / matcher->get_submatch( 1 ).
ENDWHILE.

Variante 2 (cl_abap_matcher)

* mehrere Submatches in einer vorgegebenen Ordnerstruktur finden
* Ordnerstruktur mit '/category/<Zahlen>/item/<Zahlen>'
DATA(matcher) = cl_abap_matcher=>create( pattern     = '^/category/([0-9]{1,5})/item/([0-9]{1,2})$'
                                         text        = '/category/12345/item/12'
                                         ignore_case = abap_true ).

IF abap_true = matcher->match( ).
* erstes Match
  WRITE: / matcher->get_submatch( 1 ).
* zweites Match
  WRITE: / matcher->get_submatch( 2 ).
ENDIF.

Variante 3 (FIND ALL OCCURRENCES OF REGEX)

* Ordnerstruktur mit '/category/<Zahlen>/item/<Zahlen>'
DATA(lv_regex) = '^/category/([0-9]{1,5})/item/([0-9]{1,2})$'.
DATA(lv_text) = '/category/12345/item/12'.

* Alle Auftreten des Suchmusters
FIND ALL OCCURRENCES OF REGEX lv_regex IN lv_text RESULTS DATA(it_results).

* Ausgabe
LOOP AT it_results ASSIGNING FIELD-SYMBOL(<r>).
  LOOP AT <r>-submatches ASSIGNING FIELD-SYMBOL(<s>).
    WRITE: / substring( val = lv_text off = <s>-offset len = <s>-length ).
  ENDLOOP.
ENDLOOP.

Variante 4 (FIND REGEX)

DATA(lv_regex) = '^/category/([0-9]{1,5})/item/([0-9]{1,2})$'.
DATA(lv_text) = '/category/12345/item/12'.

* Erstes Auftreten des Suchmusters
FIND REGEX lv_regex IN lv_text RESULTS DATA(lv_results).

LOOP AT lv_results-submatches ASSIGNING FIELD-SYMBOL(<s>).
  WRITE: / substring( val = lv_text off = <s>-offset len = <s>-length ).
ENDLOOP.

[ABAP] RegEx: Bestimmte Nodes (Submatches) in einem XML-String finden

* XML
DATA(lv_xml) = |<person>| &&
               |  <name>Udo</name>| &&
               |  <age>25</age>| &&
               |</person>| &&
               |<person>| &&
               |  <name>Ede</name>| &&
               |  <age>34</age>| &&
               |</person>| &&
               |<person>| &&
               |  <name />| &&
               |  <age>78</age>| &&
               |</person>|.

* Alle Nodes mit <name>...</name> finden
DATA(matcher) = cl_abap_matcher=>create( pattern     = '<name>([[:alnum:]]*)</name>'
                                         text        = lv_xml
                                         ignore_case = abap_true ).

* Alle Suchergebnisse ausgeben
WHILE abap_true = matcher->find_next( ).
  WRITE: / matcher->get_submatch( 1 ).
ENDWHILE.

[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] PDF-Dokument per ADS (Adobe Document Service) in XML konvertieren

* https://www.berater-wiki.de/XML_aus_PDF_extrahieren_mit_Testprogramm_FP_PDF_TEST_03
* http://sapfirst.blogspot.com/2014/05/inbound-abap-proxy-with-pdf-attachment.html
* Paket:     SAFP
* Programme: FP_PDF_TEST_01 (PDF erzeugen)
*            FP_PDF_TEST_03 (Datenextraktion)
* XFD (XML Form Data): https://www.berater-wiki.de/XFD-Datei_(Values_of_PDF_form_fields_in_XML)
* XFT (XML Form Template)
* XDC (XML Printer Definitions)

TRY.
    DATA: lv_rc TYPE i.
    DATA: it_files TYPE filetable.
    DATA: lv_action TYPE i.

* FileOpen-Dialog aufrufen
    cl_gui_frontend_services=>file_open_dialog( EXPORTING
                                                  file_filter    = |pdf (*.pdf)\|*.pdf\|{ cl_gui_frontend_services=>filetype_all }|
                                                CHANGING
                                                  file_table  = it_files
                                                  rc          = lv_rc
                                                  user_action = lv_action ).

    IF lv_action = cl_gui_frontend_services=>action_ok.
* wenn mind. zwei Dateien ausgewählt worden sind
      IF lines( it_files ) > 0.
        DATA(lv_filesize) = CONV w3param-cont_len( '0' ).
        DATA(it_bin_data) = VALUE w3mimetabtype( ).

* Datei auf Appl. Server hochladen (binary)
        cl_gui_frontend_services=>gui_upload( EXPORTING
                                                filename   = |{ it_files[ 1 ]-filename }|
                                                filetype   = 'BIN'
                                              IMPORTING
                                                filelength = lv_filesize
                                              CHANGING
                                                data_tab   = it_bin_data ).

* solix -> xstring
        DATA(lv_bin_data) = cl_bcs_convert=>solix_to_xstring( it_solix = it_bin_data ).

* Form Processor erzeugen
        DATA(o_form_processor) = cl_fp=>get_reference( ).
* PDF-Objekt erzeugen
        DATA(o_pdf) = o_form_processor->create_pdf_object( ).
* Binärdaten an PDF-Objekt übergeben
        o_pdf->set_document( pdfdata = lv_bin_data ).
* PDF-Daten extrahieren
        o_pdf->set_extractdata( ).
* ADS-Server rufen
        o_pdf->execute( ).
* extrahierte Daten holen (xstring)
        o_pdf->get_data( IMPORTING formdata = DATA(lv_pdf_formdata) ).

* xstring (binary) -> XML-string (UTF-8)
        DATA(lv_pdf_xml_str) = ||.
        DATA(o_conv) = cl_abap_conv_in_ce=>create( input    = lv_pdf_formdata
                                                   encoding = 'UTF-8' ).
        o_conv->read( IMPORTING data = lv_pdf_xml_str ).

* XML-Zugriff
        DATA(o_ixml) = cl_ixml=>create( ).

        DATA(o_sf) = o_ixml->create_stream_factory( ).
        DATA(o_doc) = o_ixml->create_document( ).
        DATA(o_stream) = o_sf->create_istream_string( lv_pdf_xml_str ).

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

* XML parsen
        IF o_parser->parse( ) = 0.

          DATA(o_root) = o_doc->get_root_element( ).

          ...

        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.

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

[ABAP] Base64 codierten String in Binärdaten (RAW) konvertieren und mit GZIP dekomprimieren

/iwwrk/cl_mgw_workflow_rt_util

TRY.
* Base64 String welcher GZIP-komprimierte Binärdaten beinhaltet
    DATA(lv_base64_data) = |C0ktLikuKcrMS1dIO7ynSCElM1XBOz+3oCi1uDgzP08hN7NEwT3KM0APAA==|.

* Base64 decodieren
    DATA(lv_xstr_gzip) = /iwwrk/cl_mgw_workflow_rt_util=>base64_decode( lv_base64_data ).

* Binärdaten
    DATA: lv_xstr TYPE xstring.
    cl_abap_gzip=>decompress_binary( EXPORTING gzip_in = lv_xstr_gzip IMPORTING raw_out = lv_xstr ).

    DATA: lv_str TYPE string.

* xstring (binary) -> string (UTF-8)
    DATA(o_conv) = cl_abap_conv_in_ce=>create( input    = lv_xstr
                                               encoding = 'UTF-8' ).
    o_conv->read( IMPORTING data = lv_str ).

    WRITE: / lv_str.

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

SSFC_BASE64_DECODE

* Base64 String welcher GZIP-komprimierte Binärdaten beinhaltet
DATA(lv_base64_data) = |C0ktLikuKcrMS1dIO7ynSCElM1XBOz+3oCi1uDgzP08hN7NEwT3KM0APAA==|.

* Binärdaten
DATA: lv_xstr TYPE xstring.
DATA: lv_xstr_gzip TYPE xstring.

* Base64 decodieren
CALL FUNCTION 'SSFC_BASE64_DECODE'
  EXPORTING
    b64data                  = lv_base64_data
  IMPORTING
    bindata                  = lv_xstr_gzip
  EXCEPTIONS
    ssf_krn_error            = 1
    ssf_krn_noop             = 2
    ssf_krn_nomemory         = 3
    ssf_krn_opinv            = 4
    ssf_krn_input_data_error = 5
    ssf_krn_invalid_par      = 6
    ssf_krn_invalid_parlen   = 7
    OTHERS                   = 8.

IF sy-subrc = 0.
  cl_abap_gzip=>decompress_binary( EXPORTING gzip_in = lv_xstr_gzip IMPORTING raw_out = lv_xstr ).

  DATA: lv_str TYPE string.

* xstring (binary) -> string (UTF-8)
  DATA(o_conv) = cl_abap_conv_in_ce=>create( input    = lv_xstr
                                             encoding = 'UTF-8' ).
  o_conv->read( IMPORTING data = lv_str ).

  WRITE: / lv_str.
ENDIF.

[ABAP] Konvertierung einer Struktur in Binärdaten (x, xstring) und zurück

Variante 1 (FIELD-SYMBOLS, CASTING: Struktur <-> Typ x)

* einfachen Typ deklarieren
TYPES: BEGIN OF ty_struct,
         matnr TYPE matnr,
         int   TYPE i,
         float TYPE f,
         text  TYPE char10,
       END OF ty_struct.

* Feldsymbol für Binärdaten
FIELD-SYMBOLS <x> TYPE x.
* Feldsymbol für Strukturdaten
FIELD-SYMBOLS <s> TYPE ty_struct.

* Struktur anlegen, deren Daten kovertiert werden soll
DATA(lv_s) = VALUE ty_struct( matnr = '1234567890'
                              int   = 1
                              float = '1.1'
                              text  = 'abc' ).

* Struktur in Binärdaten umwandeln
ASSIGN lv_s TO <x> CASTING.
IF <x> IS ASSIGNED.
* Binärdaten in Struktur umwandeln
  ASSIGN <x> TO <s> CASTING.
  IF <s> IS ASSIGNED.
    DATA(lv_s2) = <s>.
* Datenausgabe
    WRITE: / lv_s2-matnr.
    WRITE: / lv_s2-int.
    WRITE: / lv_s2-float.
    WRITE: / lv_s2-text.
  ENDIF.
ENDIF.

Variante 2 (xstring -> Struktur)

* https://www.consolut.com/s/sap-ides-zugriff/d/e/doc/M-CL_ABAP_CONV_IN_CE/
* einfachen Typ deklarieren
TYPES: BEGIN OF ty_struct,
         text TYPE char5,
         int  TYPE i,
       END OF ty_struct.

* Zielstruktur
DATA(lv_s) = VALUE ty_struct( ).

* Konverterobjekt mit UTF-8 und Little Endian Konvertierung
DATA(o_conv) = cl_abap_conv_in_ce=>create( encoding = 'UTF-8' endian = 'L' ).
* View-Objekt
DATA(o_view) = cl_abap_view_offlen=>create_legacy_view( lv_s ).
* Eingabepuffer mit Binärdaten
DATA(lv_buffer) = CONV xstring( '616263202000000005000000' ).

* Konvertierung xstring -> Struct
*  in: HEX: 616263202000000005000000
* out: Struct: text: abc
*               ínt: 5
o_conv->convert_struc( EXPORTING
                         input = lv_buffer
                         view  = o_view
                       IMPORTING
                         data  = lv_s ).

* Datenausgabe
WRITE: / lv_s-text.
WRITE: / lv_s-int.

Variante 3 (Struktur -> xstring)

* https://www.consolut.com/s/sap-ides-zugriff/d/e/doc/M-CL_ABAP_CONV_OUT_CE/
* einfachen Typ deklarieren
TYPES: BEGIN OF ty_struct,
         text TYPE char5,
         int  TYPE i,
       END OF ty_struct.

* Struktur mit Quelldaten
DATA(lv_s) = VALUE ty_struct( text = 'abc'
                              int  = 5 ).

* Konverterobjekt mit UTF-8 und Little Endian Konvertierung
DATA(o_conv) = cl_abap_conv_out_ce=>create( encoding = 'UTF-8' endian = 'L' ).
* View-Objekt
DATA(o_view) = cl_abap_view_offlen=>create_legacy_view( lv_s ).
* Ausgabepuffer für Binärdaten
DATA: lv_buffer type xstring.

* Konvertierung Struct -> xstring
*  in: Struct: text: abc
*               ínt: 5
* out: HEX: 616263202000000005000000
o_conv->convert_struc( EXPORTING
                         data   = lv_s
                         view   = o_view
                       IMPORTING
                         buffer = lv_buffer ).

* Datenausgabe
WRITE: / lv_buffer.