[ABAP] XLSX-Datei mit Klasse cl_ehfnd_xlsx einlesen und in SALV-Grid anzeigen

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 = |xlsx (*.xlsx)\|*.xlsx\|{ 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 Datei ausgewählt wurde
      IF lines( it_files ) > 0.
* ersten Tabelleneintrag lesen
        DATA: lv_filesize TYPE w3param-cont_len.
        DATA: lv_filetype TYPE w3param-cont_type.
        DATA: it_bin_data TYPE w3mimetabtype.

* Excel-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 ).

**********************************************************************
* XLSX Handling: Kapselt cl_xlsx_document
**********************************************************************
        DATA(o_excel) = cl_ehfnd_xlsx=>get_instance( ).

* XLSX Workbook (XString --> XML)
        DATA(o_doc) = o_excel->load_doc( iv_file_data = lv_bin_data ).

* XLSX Sheets des Workbooks holen
        DATA(it_sheets) = o_doc->get_sheets( ).

        IF lines( it_sheets ) > 0.
* XLSX Sheet: erste Sheet holen
          DATA(o_sheet) = o_doc->get_sheet_by_id( iv_sheet_id = 1 ).
          DATA(lv_sheet_name) = it_sheets[ 1 ]-name.

* max. Zeilenzahl der Sheet
          DATA(lv_max_rows) = o_sheet->get_last_row_number( ).
          DATA(lv_max_cols) = o_sheet->get_last_column_number_in_row( 1 ).

          IF lv_max_rows > 0 AND lv_max_cols > 0.
* Komponenten (Spalten) der Tabelle --> generische Stringtable bauen
            DATA(it_components) = VALUE cl_abap_structdescr=>component_table( ).

* Überschriften (Header) für ALV-Grid
            DATA(it_colnames) = VALUE stringtab( ).

            DO lv_max_cols TIMES.
* Spaltenbezeichner aus 1. Zeile (Header) der Excel-Tabelle holen
              DATA(lv_col_header) = o_sheet->get_cell_content( iv_row    = 1
                                                               iv_column = sy-index ).

* alle Vorkommen, die nicht [a-zA-Z0-9_] entsprechen, durch '_' ersetzen
              REPLACE ALL OCCURRENCES OF REGEX '([^\w]|[äöüÄÖÜß])+' IN lv_col_header WITH '_'.

* Tabelle mit Überschriften für ALV-Grid füllen
              APPEND lv_col_header TO it_colnames.

* Spalte vom Typ String mit generischem Namen zur Komponententabelle hinzufügen
              APPEND VALUE #( name   = |COL{ sy-index }|
                              type   = cl_abap_elemdescr=>get_string( )
                            ) TO it_components.
            ENDDO.

**********************************************************************
* generische interne Tabelle mit hilfe dynamischer Objekte erzeugen
**********************************************************************
* Strukturdeskriptor für Komponententabelle erzeugen
            DATA(o_struct_desc) = cl_abap_structdescr=>create( it_components ).

* Tabellendeskriptor erzeugen
            DATA(o_table_desc) = cl_abap_tabledescr=>create( p_line_type = o_struct_desc ).

* dynamisches Tabellenobjekt anhand des Tabellendeskriptors erstellen
            DATA: o_table TYPE REF TO data.
            CREATE DATA o_table TYPE HANDLE o_table_desc.

* Feldsymbol auf das Tabellenobjekt vom Typ STANDARD TABLE anlegen
            FIELD-SYMBOLS <table> TYPE STANDARD TABLE.
            ASSIGN o_table->* TO <table>.

* Inhalt (ohne Header) aus XLSX in interne Tabelle schreiben
            DATA(lv_row) = 2.

            DO lv_max_rows - 1 TIMES.
              DATA(lv_col) = 1.

* neue Ausgabezeile anfügen
              APPEND INITIAL LINE TO <table>.

* neue Ausgabezeile holen und Feldsymbol zuweisen
              DATA(lv_lc) = lines( <table> ).
              ASSIGN <table>[ lv_lc ] TO FIELD-SYMBOL(<row>).

              IF <row> IS ASSIGNED.
* für alle Spalten der Tabelle
                DO lv_max_cols TIMES.
* n-te Spalte <col> der akt. Tabellenzeile <row> ermitteln
                  ASSIGN COMPONENT lv_col OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
                  IF <cell> IS ASSIGNED.
* Inhalt der akt. Zelle in die Zelle der internen Tabelle schreiben
                    <cell> = o_sheet->get_cell_content( iv_row    = lv_row
                                                        iv_column = lv_col ).


                  ENDIF.

                  lv_col = lv_col + 1.
                ENDDO.
              ENDIF.

              lv_row = lv_row + 1.
            ENDDO.

**********************************************************************
* Anzeige der gefüllten generischen Tabelle in einem SALV-Grid
**********************************************************************
            TRY.
*             SALV-Table
                DATA: o_salv TYPE REF TO cl_salv_table.

                cl_salv_table=>factory( IMPORTING r_salv_table = o_salv
                                        CHANGING  t_table      = <table> ).

*             Grundeinstellungen
                o_salv->get_functions( )->set_all( abap_true ).
                o_salv->get_columns( )->set_optimize( abap_true ).
                o_salv->get_display_settings( )->set_list_header( CONV #( lv_sheet_name ) ).
                o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
                o_salv->get_selections( )->set_selection_mode( if_salv_c_selection_mode=>row_column ).

*             Spaltenüberschriften: technischer Name und Beschreibungstexte, Short Text und Medium Text leer lassen für Autosize
                LOOP AT o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
                  DATA(lv_idx) = sy-tabix.

                  DATA(o_col) = <c>-r_column.
                  o_col->set_short_text( || ).
                  o_col->set_medium_text( || ).
                  o_col->set_long_text( CONV #( it_colnames[ lv_idx ] ) ).
                ENDLOOP.

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

        ENDIF.

      ENDIF.

    ENDIF.

  CATCH cx_root INTO DATA(e_text).
    MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.

[ABAP] MS-Excel-Datei mit Hilfe der Klasse cl_ehfnd_xlsx lesen

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 = |xlsx (*.xlsx)\|*.xlsx\|{ 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 Datei ausgewählt wurde
      IF lines( it_files ) > 0.
* ersten Tabelleneintrag lesen
        DATA: lv_filesize TYPE w3param-cont_len.
        DATA: lv_filetype TYPE w3param-cont_type.
        DATA: it_bin_data TYPE w3mimetabtype.

* Excel-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 ).

* XLSX Handling: Kapselt cl_xlsx_document
        DATA(o_excel) = cl_ehfnd_xlsx=>get_instance( ).

* XLSX Workbook (XString --> XML)
        DATA(o_doc) = o_excel->load_doc( iv_file_data = lv_bin_data ).

* XLSX Sheets des Workbooks holen
        DATA(it_sheets) = o_doc->get_sheets( ).

        LOOP AT it_sheets ASSIGNING FIELD-SYMBOL(<sheet>).
          WRITE: / <sheet>-name, <sheet>-sheet_id, <sheet>-rid.
        ENDLOOP.

        ULINE.

* XLSX Sheet: erste Sheet holen
        DATA(o_sheet) = o_doc->get_sheet_by_id( iv_sheet_id = 1 ).
* max. Zeilenzahl der Sheet
        DATA(lv_maxrow) = o_sheet->get_last_row_number( ).

        DATA(lv_row) = 1.

        DO lv_maxrow TIMES.
* max. Spaltenzahl der akt. Zeile
          DATA(lv_cols_in_row) = o_sheet->get_last_column_number_in_row( lv_row ).
          DATA(lv_col) = 1.

          DO lv_cols_in_row TIMES.
* Inhalt der akt. Zelle
            DATA(lv_value) = o_sheet->get_cell_content( EXPORTING iv_row    = lv_row
                                                                  iv_column = lv_col ).

            WRITE: lv_value.

            lv_col = lv_col + 1.
          ENDDO.

          lv_row = lv_row + 1.

          WRITE: /.
        ENDDO.

      ENDIF.
    ENDIF.

  CATCH cx_root INTO DATA(e_text).
    MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.

[ABAP] Beispiel für Verwendung der Klasse cl_xlsx_document

* Workbook
PARAMETERS: p_wb RADIOBUTTON GROUP grp DEFAULT 'X'.
* Sharedstrings
PARAMETERS: p_str RADIOBUTTON GROUP grp.
* Sheetpart
PARAMETERS: p_sh RADIOBUTTON GROUP grp.
* Tablepart
PARAMETERS: p_tab RADIOBUTTON GROUP grp.

START-OF-SELECTION.

  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 = |xlsx (*.xlsx)\|*.xlsx\|{ 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 Datei ausgewählt wurde
        IF lines( it_files ) > 0.
* ersten Tabelleneintrag lesen
          DATA: lv_filesize TYPE w3param-cont_len.
          DATA: lv_filetype TYPE w3param-cont_type.
          DATA: it_bin_data TYPE w3mimetabtype.

* Excel-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 ).

**********************************************************************
* Excel-Objekt
**********************************************************************
          DATA(o_excel) = cl_xlsx_document=>load_document( lv_bin_data ).

          DATA(o_workbook) = o_excel->get_workbookpart( ).
          DATA(lv_workbook_xstr) = o_workbook->get_data( ).

          DATA(o_sharedstrings) = o_workbook->get_sharedstringspart( ).
          DATA(lv_sharedstrings_xstr) = o_sharedstrings->get_data( ).

          DATA(o_sheets) = o_workbook->get_worksheetparts( ).
          IF o_sheets->get_count( ) > 0.
            DATA(o_sheet) = CAST cl_xlsx_worksheetpart( o_sheets->get_part( 0 ) ).

            DATA(lv_sheet_xstr) = o_sheet->get_data( ).

            DATA(o_tables) = o_sheet->get_tableparts( ).
            IF o_tables->get_count( ) > 0.
              DATA(o_table) = CAST cl_xlsx_tablepart( o_tables->get_part( 0 ) ).
              DATA(lv_table_xstr) = o_table->get_data( ).
            ENDIF.
          ENDIF.

* XML Doc
          DATA(o_doc) = NEW cl_xml_document( ).

* xstring --> xml
          CASE abap_true.
            WHEN p_wb.
              o_doc->parse_xstring( lv_workbook_xstr ).
            WHEN p_str.
              o_doc->parse_xstring( lv_sharedstrings_xstr ).
            WHEN p_sh.
              o_doc->parse_xstring( lv_sheet_xstr ).
            WHEN p_tab.
              o_doc->parse_xstring( lv_table_xstr ).
          ENDCASE.

* Inhalt des XML-Documents in string wandeln
          o_doc->render_2_string( EXPORTING pretty_print = abap_true
                                  IMPORTING retcode      = DATA(lv_rc2)
                                            size         = DATA(lv_size2)
                                            stream       = DATA(lv_xml) ).

          IF lv_rc2 = 0.
* XML-String anzeigen
            cl_soap_xml_helper=>xml_show( sdoc  = lv_xml
                                          html  = abap_true
                                          title = 'XML Anzeige' ).
          ENDIF.

        ENDIF.
      ENDIF.

    CATCH cx_root INTO DATA(e_text).
      MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
  ENDTRY.

[ABAP] XML-Daten anzeigen

* XML-String
DATA(lv_xml_string) = |<?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>|.

* Display XML document
cl_soap_xml_helper=>xml_show(
                              sdoc = lv_xml_string  " XML as character string
*                              xdoc =               " XML as binary string
                              html = abap_false     " HTML or XML
*                              new_window =         " New SAPGUI
                              title = 'XML Anzeige' " DEFAULT 'Document display'(001)
                            ).

[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] XML-Datei einlesen und in String wandeln

TRY.
    DATA(o_doc) = NEW cl_xml_document( ).
* XML-Datei einlesen
    IF o_doc->import_from_file( 'c:\temp\temp.xml' ) = 0.
* Inhalt der XML-Document in String wandeln
      o_doc->render_2_string( EXPORTING
                                pretty_print = abap_true
                              IMPORTING
                                retcode = DATA(lv_rc)
                                size    = DATA(lv_size)
                                stream  = DATA(lv_xml_string) ).
      IF lv_rc = 0.
        WRITE: / lv_xml_string.
      ENDIF.
    ENDIF.
  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

[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.