VNSG Magazine | september 2014
CRM en MS Excel Introductie Met SAP CRM en de WebUI kan een gebruiker heel goed uit de voeten. Echter soms wil men simpelweg de gegevens uit CRM extern in een ander pakket gebruiken. Vaak wordt dan gekozen voor een MS Excel werkblad, die dan gevuld wordt met gegevens uit CRM. SAP heeft daarvoor diverse oplossingen. Er is zelfs een oplossing, waarbij men zelf invloed kan uitoefenen voordat gegevens daadwerkelijk worden geëxporteerd. Daarnaast bestaat de mogelijkheid om vanuit MS Excel gegevens in SAP CRM op te nemen, waarbij men natuurlijk wel zelf een kort programma moet maken. Met deze tip & trick gaan we in op die stappen die men in CRM uitvoert om gebruik te maken van MS Excel werkbladen.
Voorbereiding We gaan ervanuit, dat we in CRM het exporteren naar en importeren van een MS Excel bestand zullen koppelen met een bestaande (maatwerk) BSP. Mocht er nog geen maatwerk BSP aanwezig zijn, dan is die eenvoudig aan te leggen via transactie SE80. Kies in de object navigator “BSP-applicatie” en geef uw eigen naam op (bijvoorbeeld: ZBSP_VNSG_EXCEL).
Buiten het invoeren van een omschrijving heeft het verder niets omhanden. Verder moet natuurlijk MS Excel aanwezig zijn op het systeem, waar de te laden gegevens moeten worden geïmporteerd.
Om te controleren of MS Excel beschikbaar is, gebruik de functiebouwsteen RH_CHECK_EXCEL_SUPPORT. Die levert zowel het programma (met pad) als ook de versie terug.
Exporteren vanuit CRM Vanuit een BSP view te kunnen exporteren, maken we gebruik van een eigen XML template, die we toevoegen aan de Excel template. Zoals in de huidige wereld gebruikelijk is, maken we aan aantal aparte methoden in de controller van onze BSP applicatie. We maken een eigen BSP controller aan met de naam export2Excel.do. Met de rechtermuisknop op de BSP naam, kiezen we Creëren Controller.
Vul de naam en omschrijving in.
Blad 1
Geef op het scherm een naam voor de controllerklasse op (uit de customer namespace). De overige velden/parameters mogen blijven, zoals ze zijn.
Sla het werk op (toets Ctrl+S). Dit waren de voorbereidende stappen. We gaan onze eigen gedefinieerde controllerklasse aanpassen en uitbreiden met wat ABAP programma code. Dubbelklik op de naam van de controllerklasse (hier is dat ZCL_EXPORT2EXCEL). U krijgt de waarschuwing, dat de klasse nog niet is aangelegd en dat moet nu gebeuren. Als de controllerklasse op het scherm verschijnt, kunt u vaststellen, dat SAP CRM automatisch al de superklasse CL_BSP_CONTROLLER2 heeft toegevoegd. Onze acties zijn nu om de methode DO_REQUEST opnieuw te definiëren en onze eigen methoden toe te voegen, ter ondersteuning. Omdat binnen view de data veelal als XML bestaat, zal de methode DO_REQUEST dus een XML transformatie gebruiken om uiteindelijk een MS Excel bestand op te leveren. Daarvoor moeten we de XML toevoegen aan de Excel template. Dat gat niet zomaar. - De XML moet UTF-8 worden gecodeerd. - De Excel template moet worden opgehaald. - Onze XML moet aan die Excel template worden toegevoegd. - En dan moeten we de export regelen. Als eerste gaan we, ter ondersteuning, een eigen XML coderen. Als voorbeeld neem ik een korte enkele XML string, maar het idee is natuurlijk, dat uw data in XML formaat wordt aangeboden. Dat kan met een IMPORTING parameter, maar die laat ik nu even weg.
We leggen de beschermde (protected) methode PREPARE_XML aan. De interface kent de volgende onderdelen:
Nu wordt het zaak om de juiste ABAP code toe te voegen.
Blad 2
METHOD prepare_xml. CONSTANTS: co_encod TYPE DATA: lv_xml4xlsx TYPE lr_convert TYPE lengte TYPE
abap_encod VALUE 'UTF-8'. string, REF TO cl_abap_conv_out_ce, i.
"XML coderen (UTF-8) lr_convert = cl_abap_conv_out_ce=>create( encoding = co_encod ). "De feitelijke XML, die wordt gebruikt (voorbeeld) "U kunt hier de eigen XML toevoegen (eventueel via een import parameter) lv_xml4xlsx = '<xmlXLS value="Voorbeeld van een correcte XML" />'. "#EC NOTEXT "Correct gecodeerde XML maken (de lengte hebben we verder niet nodig) lr_convert->convert( EXPORTING data = lv_xml4xlsx IMPORTING buffer = ev_xml4xlsx len = lengte ). ENDMETHOD.
We hebben de Excel template nodig. Die moeten we echter wel in de MIME repository laden (als dat nog niet is gebeurd). Omdat niet duidelijk is, waar de Excel template is geladen, zult u die informatie zelf moeten bepalen. Het aanleggen van een eigen template kan via transactie SE80 en de browser keuze MIME Repository. Als deze niet beschikbaar is, kunt u dat inschakelen via het menu: Hulpmiddelen Instellingen Op het tabblad Workbench algemeen schakelt u MIME Repository in. Zoek in de MIME Repository naar de eigen BSP. SAP BC BSP SAP ZBSP_VNSG_EXCEL We gaan de template hieronder maken. Dat wordt in feite een leeg Excel bestand. De documentklasse is M_APP_P. Kies een naam en vergeet niet de juiste extensie mee te geven (.xlsx). Overigens is dit wel afhankelijk van de versie van MS Excel, die u gebruikt. Voor de oudere types (.xls bestanden) kiest u het MIME-type application/ms-excel. Voor de nieuwe types (.xlsx) kiest u het MIME-type application/vnd.ms-excel. Er bestaat ook een open formaat voor .xlsx. Daarvoor moet u dan met MIME type application/vnd.openxmlformats-officedocument.spreadsheetml.sheet kiezen.
Blad 3
Druk op Editor starten. SAP GUI kan u waarschuwen, dat er toestemming moet worden verleend. Dat doen we. Daarna wordt MS Excel opgestart met de door u gekozen naam. Sla het bestand op en sluit MS Excel af. We gaan terug naar onze BSP applicatie. Als u de refresh gebruikt, ziet u, dat de BSP applicatie nu een MIME bevat met de gekozen naam (hier is dat Template.xlsx). Dit is nu het Excel template dat we gaan gebruiken en die moet natuurlijk is de BSP worden geladen. Daarvoor maken we een nieuwe beschermen (protected) methode aan. We geven de naam GET_XLSX_TEMPLATE.
Met de volgende interface.
Blad 4
Toevoegen ABAP code. METHOD get_xlsx_template. DATA: lr_mr_api TYPE REF TO if_mr_api, xls_template TYPE string VALUE 'Template.xlsx'. "MIME Repository API object lr_mr_api = cl_mime_repository_api=>get_api( ). "Lezen XLSX template lr_mr_api->get( EXPORTING i_url = xls_template IMPORTING e_content = ev_xlsx EXCEPTIONS OTHERS = 0 ). ENDMETHOD.
Nu kunnen we de beide onderdelen, XML data en Excel template samenvoegen in een XML stroom. Daarvoor maken we methode PUT_XML2XLSX aan met de volgende interface.
De bijbehorende ABAP code. METHOD put_xml2xlsx. DATA: xlsx workbookpart packagecontent customxmlpartcoll customxmlpart customxmlpropspart propertyxml preguid guid
TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE
REF TO cl_xlsx_document, REF TO cl_xlsx_workbookpart, string, REF TO cl_openxml_partcollection, REF TO cl_oxml_customxmlpart, REF TO cl_oxml_customxmlpropspart, xstring, string, string.
Blad 5
"Beschermde uitvoering TRY. "MS Excel xlsx = packagecontent = workbookpart = customxmlpartcoll = customxmlpart =
cl_xlsx_document=>load_document( iv_data = iv_xlsx ). xlsx->get_content_type( ). xlsx->get_workbookpart( ). workbookpart->get_customxmlparts( ). workbookpart->add_customxmlpart( ).
"Toevoegen XML data customxmlpart->feed_data( iv_xml
).
"GUID (Omsluiten met {...} accolades) customxmlpropspart = customxmlpart->add_customxmlpropspart( ). preguid = cl_openxml_helper=>create_guid_string( ). CONCATENATE '{' preguid '}' INTO guid. "Aanleggen eigen XML attribuut (inhoud) CALL TRANSFORMATION docx_create_custompropscontent PARAMETERS guid = guid SOURCE XML iv_xml RESULT XML propertyxml. "Toevoegen XML attribuut customxmlpropspart->feed_data( propertyxml ). "Retour XLSX ev_xlsx = xlsx->get_package_data( ). CATCH cx_openxml_format. CATCH cx_openxml_not_allowed. CATCH cx_openxml_not_found. CATCH cx_transformation_error. RAISE xslt_error. ENDTRY. ENDMETHOD.
Er moet een methode bestaan om de gecombineerde gegevens op te halen. Die maakt natuurlijk gebruik van de eerder behandelde methodes. Om de te exporteren gegevens op te halen (“single method sollution”) wordt een nieuwe methode gemaakt GET_XLSX_EXPORT_DATA met de onderstaande interface.
Blad 6
Aangevuld met ABAP code. METHOD get_xlsx_export_data. DATA: lv_xml4xlsx TYPE xstring, lv_xlsx_template TYPE xstring. "Voorbereiden van de XML prepare_xml( IMPORTING ev_xml4xlsx = lv_xml4xlsx EXCEPTIONS xslt_error = 1 OTHERS = 2 ). IF sy-subrc EQ 1. RAISE xslt_error. ELSEIF sy-subrc EQ 2. RAISE process_error. ENDIF. "Ophalen Excel template get_xlsx_template( IMPORTING ev_xlsx = lv_xlsx_template ). "Toevoegen van eigen XML aan Excel template put_xml2xlsx( EXPORTING iv_xlsx = lv_xlsx_template iv_xml = lv_xml4xlsx IMPORTING ev_xlsx = ev_xml_xlsx EXCEPTIONS xslt_error = 1 OTHERS = 2 ). IF sy-subrc EQ 1. RAISE xslt_error. ELSEIF sy-subrc EQ 2. RAISE process_error. ENDIF. ENDMETHOD.
Nu hebben we alle extra methoden aangelegd. Denk eraan, dat in dit voorbeeld er geen echte data wordt geïmporteerd, maar dat laat ik over aan de ontwikkelaars. Het is namelijk de bedoeling, dat de BSP wordt geïntegreerd met andere BSP’s die een MS Excel export willen hebben. De data (vanuit de front-end browser) is veelal in XML beschikbaar (intern wordt dan het type XSTRING gebruikt). Simpel die data toevoegen als de XML data in de methode PREPARE_XML is voldoende. Dat zal natuurlijk voor elke BSP, waarin u deze BSP koppelt net iets anders zijn. Vandaar.
Blad 7
Om de BSP functie te gebruiken, moeten we de methode DO_REQUEST in onze controller opnieuw definiëren.
Selecteer de methode DO_REQUEST en druk op de knop voor herdefinitie. Hiermee bent u in staat om eigen ABAP code toe te voegen aan deze methode. Even ter herinnering. De MS Excel template, die u heeft aangelegd heeft een specifiek type. U moet dit MIME type gebruiken als content-type bij het zetten van de RESPONSE. Voor .XLS was het MIME type application/ms-excel. Voor .XLSX was het MIMI type application/vnd.ms-excel. Voor het open formaat .XLSX (met andere pakketten te openen) was het type application/vnd.openxmlformats-officedocument.spreadsheetml.sheet. Hiermee is alle informatie voor de ABAP code in de DO_REQUEST methode bekend.
Blad 8
METHOD do_request. DATA: lv_xlsx TYPE xstring, lengte TYPE i. "Eventuele logica in de superklasse uitvoeren super->do_request( ). "Ophalen van te exporteren data get_xlsx_export_data( IMPORTING ev_xml_xlsx = lv_xlsx EXCEPTIONS error_occurred = 1 ). lengte = xstrlen( lv_xlsx ). "Exporteer RESPONSE data response->if_http_entity~append_data( EXPORTING data = lv_xls length = lengte ). "Zet het RESPONSE content-type op Excel response->if_http_entity~set_header_field( EXPORTING name = 'content-type' value = 'application/vnd.ms-excel' ).
"#EC NOTEXT "#EC NOTEXT
ENDMETHOD.
Nu is alles gereed. Zorg ervoor dat de gehele controller klasse gecompileerd en geactiveerd is. Repareer eventuele foutjes. Ga daarna naar de BSP applicatie terug (ZBSP_VNSG_EXCEL) en activeer deze.
Blad 9
Deze controller kunt u overnemen in uw eigen BSP en gebruiken om uw tabel data naar een MS Excel bestand om te zetten. Zorg er wel voor, dat uw data uit de BSP (of de HTML code) in een XML stroom als XSTRING type beschikbaar is. In deze tip is alleen een kleine XML string gebruikt, maar in principe zit er geen limiet aan de grootte. Importeren naar CRM toe Een BSP view van externe gegevens voorzien uit een MS Excel bestand is niet erg handig. Je kunt gewoon de MS Excel direct openen om de inhoud te zien. Dus voor de import gaan we naar de achtergrond in het SAP CRM systeem. We maken een globale methode, die een willekeurige MS Excel bestand kan inlezen. Voor verdere verwerking zult u dan zelf moeten zorgen. Deze tip beschrijft alleen de stappen voor de import, waarbij we gebruik maken van componenten op de lokale computer. Ook hier bouwen we een klasse met methoden op. Met als bijzonderheid, dat een instance oproepen van het object direct leidt tot de import. U kunt individuele cellen verwerken (wat een conversie mogelijk maakt). We gaan nu in CRM zelf een object maken met de naam ZCL_EXCEL. Als we daarmee gereed zijn, kunt u met 2 simpele regels ABAP code elke willekeurige MS Excel importeren. U krijgt de import gegevens in een zeer speciaal formaat binnen. Namelijk elke MS Excel rij is in een veld opgenomen, waarbij de cel inhoud van de cellen wordt gescheiden door het pipe-teken ( | ). Een beetje ABAPper weet dan dat hij die regels dus eenvoudig kan splitsen op basis van dat pipe-teken. Via de object navigator (transactie SE80) kunt u een bestaand pakket uitbreiden met een nieuwe klasse. Rechtermuis op de pakketnaam en dan in het context menu: Creëren Klassenbibliotheek Klasse
Blad 10
Vul in de dialoog de naam (klant namengebied gebruiken) en geef een omschrijving.
Sla het object op. Omdat het importeren van MS Excel best een complexe zaak is en omdat je ook nog invloed wil kunnen uitvoeren op de ontvangen cel inhoud, moeten we een aantal zaken vooraf aanleggen. Hierbij hebben we eigen types nodig. Er bestaan wel types in de data dictionary van SAP CRM, maar die passen niet altijd. Om die reden definiëren we op het tabblad een paar typen:
Door op de knop van Directe type invoer te drukken, kunt u met ABAP code de typen verder definiëren.
Blad 11
PROTECTED SECTION. *"* protected components of class ZCL_EXCEL *"* do not include other source files here!!! TYPES: ty_c_132 TYPE c LENGTH 132 . TYPES: ty_c_4096 TYPE c LENGTH 4096 . TYPES: ty_t_excel TYPE STANDARD TABLE OF ty_c_4096 . TYPES: BEGIN OF ty_s_senderline , line TYPE ty_c_4096 , END OF ty_s_senderline . TYPES: ty_t_sender TYPE STANDARD TABLE OF ty_s_senderline . TYPES: BEGIN OF ty_s_ex_tabcell , row TYPE n LENGTH 4 , col TYPE n LENGTH 4 , value TYPE ty_c_132 , END OF ty_s_ex_tabcell . TYPES: ty_t_ex_tabcell TYPE STANDARD TABLE OF ty_s_ex_tabcell .
De typen gebruiken we deels voor attributen, deels voor methode interfaces en deels voor de interne ABAP code. De typen zijn in het beschermde deel (protected section) aangelegd om te voorkomen, dat externe programmatuur er gebruik van kan maken, maar bij overerving van het object de typen wel beschikbaar zijn.
We definiëren een paar attributen. Attribuut INSTANCE (met referentie naar ons eigen object, dus naar zichzelf) moet statisch worden gedefinieerd omdat de klasse automatisch moet worden geïnstantieerd.
-
Constante DELIMITER bevat het pipe-teken ‘|’. Constante WILDCARD bevat het sterretje-teken (asterisk) ‘*’. Attribuut MS_CELLDATA is een interne tabel, die de Excel cellen identificeren (rij en kolom) en de waarde van de cellen bevat. Attribuut MS_IMPORTED is een interne tabel, die regels bevat, waarin per regel de individuele cellen gescheiden door het pipe-teken zijn opgeslagen. Dit is ook uiteindelijk de tabel, die wordt opgeleverd.
Om straks het object ZCL_EXCEL eenvoudig te kunnen aanroepen maken we een CLASS_CONSTRUCTOR methode, die het object zal aanleggen, zodra men het statische attribuut INSTANCE gebruikt.
Blad 12
METHOD class_constructor. CREATE OBJECT instance. ENDMETHOD.
Als SAP een MS Excel importeert, dan zorgt SAP ervoor, dat de cellen gescheiden worden door een tabteken. Dat teken kan worden opgehaald uit het standaard SAP object CL_ABAP_CHAR_UTILITIES. Dit object moet dan wel al geladen zijn, anders is het tab-teken nog niet toegekend. Ook moeten we ervoor zorgen, dat de beide interne tabellen absoluut leeg zijn. Een statisch aangelegd object blijft namelijk in het geheugen beschikbaar en we willen geen oude gegevens ontvangen. Dat is dus reden om in het object ook een CONSTRUCTOR methode aan te leggen. De CONSTRUCTOR methode bevat hiervoor de nodige zaken. METHOD constructor. CLEAR: ms_celldata[], ms_imported[]. CLASS cl_abap_char_utilities DEFINITION LOAD. ENDMETHOD.
Om een MS Excel bestand te importeren, moeten we een bestand openen dialoog op kunnen roepen. Daarvoor maken we methode MS_EXCEL_FILE_DIALOG aan met de volgende interface.
De methode moet niets meer doen, dan de bestandsnaam terug leveren (met een volledig gekwalificeerd pad). Dat lijkt moeilijk, maar is erg eenvoudig. Standaard SAP CRM heeft een object CL_GUI_FRONTEND_SERVICES, die de methode FILE_OPEN_DIALOG bevat, die al het werk voor u doet. METHOD ms_excel_file_dialog. DATA: bestanden TYPE filetable, retourcode TYPE i. FIELD-SYMBOLS:
TYPE file_table. "Bestand openen dialoog CALL METHOD cl_gui_frontend_services=>file_open_dialog EXPORTING window_title = 'MS Excel bestand openen' default_extension = 'XLSX' file_filter = 'MS Excel-bestanden (*.XLS;*.XLSX)|*.XLS;*.XLSX|Alle bestanden (*.*)|*.*|' multiselection = space CHANGING file_table = bestanden rc = retourcode EXCEPTIONS OTHERS = 5.
Blad 13
IF sy-subrc NE 0. CLEAR: sy-subrc, bestandsnaam. ELSE. READ TABLE bestanden ASSIGNING INDEX 1. IF sy-subrc NE 0 OR IS NOT ASSIGNED. CLEAR: sy-subrc, bestandsnaam. RETURN. ELSE. bestandsnaam = -filename. UNASSIGN . ENDIF. ENDIF. ENDMETHOD.
Nu komt het moeilijke deel. Om een MS Excel bestand überhaupt te kunnen importeren, maken we gebruik van de OLE2 functionaliteit, die SAP standaard ondersteund. Dat leidt wel tot een hele berg ABAP code. In feite wordt er een applicatie geopend (en niet zichtbaar gemaakt). In die applicatie worden opdrachten uitgevoerd. In simpele termen markeren we in het actieve werkblad van het door ons geopende MS Excel bestand een gebied van 200 kolommen en 5000 regels. Mocht je meer willen, dan kun je dat aanpassen. Vervolgens kopiëren we dat gebied naar het klembord en daarna importeren we het klembord. BELANGRIJK Zodra de applicatie is aangelegd, wordt MS Excel op de achtergrond geladen. Die verdwijnt echter niet meer uit het geheugen, tenzij expliciet de applicatie wordt gesloten en alle gebruikte referentie objecten zijn vrijgegeven. Als u in de code er dus met een “fout” uitspringt, zult u zelf MS Excel niet goed meer kunnen starten. Om de bovenstaande reden hebben we een afwijkende foutverwerking als MACRO gedefinieerd. Via het menu kun je macro’s aanleggen. Kies Ga naar Lokale definities/implementaties Macro’s We maken de macro PROCESS_RESULT aan. "Fout verwerking DEFINE process_result. case sy-subrc. when 0. when 1. message id sy-msgid type sy-msgty number sy-msgno with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. retourcode = 1. when others. retourcode = sy-subrc. endcase. END-OF-DEFINITION.
Blad 14
Nu zijn we klaar om de import functionaliteit aan te leggen. Hiervoor maken de methode MS_EXCEL_IMPORT_DATA aan. METHOD ms_excel_import_data. DATA: excel_tab TYPE ty_t_sender, application TYPE ole2_object, workbook TYPE ole2_object, range TYPE ole2_object, worksheet TYPE ole2_object, cell_to_le TYPE ole2_object, cell_bo_ri TYPE ole2_object, retourcode TYPE i. "Bestandsnaam bestandsnaam = ms_excel_file_dialog( ). "Open Excel bestand IF application-header EQ space OR application-handle EQ -1. CREATE OBJECT application 'Excel.Application'. process_result. ENDIF.
Blad 15
CALL METHOD OF application 'Workbooks' = workbook. process_result. CALL METHOD OF workbook 'Open' EXPORTING #1 = bestandsnaam. process_result. "Bepaal actieve werkblad GET PROPERTY OF application 'ACTIVESHEET' = worksheet. process_result. "Markeer het werkblad (200 kolommen en 5000 regels) CALL METHOD OF worksheet 'Cells' = cell_to_le EXPORTING #1 = 1 #2 = 1. process_result. CALL METHOD OF worksheet 'Cells' = cell_bo_ri EXPORTING #1 = 200 "Aantal kolommen #2 = 5000. "Aantal regels process_result. "Stel gebied vast CALL METHOD OF worksheet 'RANGE' = range EXPORTING #1 = cell_to_le #2 = cell_bo_ri. process_result. "Kopiéer het geselecteerde gebied naar het Clippboard CALL METHOD OF range 'SELECT'. process_result. CALL METHOD OF range 'COPY'. process_result. "Lees het clibboard IF retourcode EQ 0. cl_gui_frontend_services=>clipboard_import( IMPORTING data = excel_tab EXCEPTIONS cntl_error = 1 OTHERS = 4 ). IF sy-subrc NE 0. retourcode = 8. ELSE. "We bewerken de tabel naar een tabel met individuele cellen convert_main_data( EXPORTING x_sep = separator CHANGING xy_excel = excel_tab xy_cells = ms_celldata "Als object attribuut gedefinieerd ).
Blad 16
"Clipboard schoonmaken (met lege tabel) CLEAR excel_tab[]. cl_gui_frontend_services=>clipboard_export( IMPORTING data = excel_tab CHANGING rc = retourcode EXCEPTIONS OTHERS = 0 ). ENDIF. ENDIF. "Stop Excel (wordt pas verwijderd als de objecten vrij worden gemaakt) CALL METHOD OF application 'QUIT'. process_result. "Housekeeping (vrij maken objecten) FREE OBJECT cell_to_le. process_result. FREE OBJECT cell_bo_ri. process_result. FREE OBJECT range. process_result. FREE OBJECT worksheet. process_result. FREE OBJECT workbook. process_result. FREE OBJECT application. process_result. "Foutverwerking IF retourcode NE 0. RAISE upload_ole. ENDIF. ENDMETHOD.
Goede lezers zullen opmerken, dat er een methode wordt gebruikt, die we nog moeten definiëren. Deze methode CONVERT_MAIN_DATA converteert de ontvangen gegevens van de kopie uit het klembord naar een interne tabel van ons eigen type TY_T_EX_TABCELL. Die bevat een veld voor de regel, kolom en waarde, waarbij alleen de gevulde cellen worden meegenomen. Die tabel moeten we later nog omzetten. De volgende interface is nodig.
Daarna kunnen we de ABAP code toevoegen.
Blad 17
METHOD convert_main_data. DATA: l_tabix TYPE sytabix, l_col TYPE kcd_ex_col, fdpos TYPE syfdpos. FIELD-SYMBOLS: <excel> TYPE ty_s_senderline, TYPE ty_s_ex_tabcell. CLEAR xy_cells[]. LOOP AT xy_excel ASSIGNING <excel>. l_tabix = sy-tabix. l_col = 0. WHILE <excel>-line CA x_sep. fdpos = sy-fdpos. l_col = l_col + 1. "Regel conversie convert_line2cell( EXPORTING x_tabix = l_tabix x_col = l_col x_sep = x_sep x_pos = fdpos CHANGING xy_line = <excel>-line xy_cells = xy_cells ). ENDWHILE. "Rest regel meenemen IF <excel>-line NE space. APPEND INITIAL LINE TO xy_cells ASSIGNING . -row = l_tabix. -col = l_col + 1. -value = <excel>-line. ENDIF. ENDLOOP. "Housekeeping IF <excel> IS ASSIGNED. UNASSIGN <excel>. ENDIF. IF IS ASSIGNED. UNASSIGN . ENDIF. ENDMETHOD.
Ook hierin wordt een methode opgeroepen, die we nog niet hebben. Deze methode, CONVERT_LINE2CELL, wordt gebruikt om een enkele regel van de Excel te verwerken. De methode CONVERT_LINE2CELL heeft een uitgebreidere interface.
Blad 18
Met de bijbehorende ABAP code METHOD convert_line2cell. DATA: l_string TYPE ty_s_senderline, l_pos TYPE i, l_cell TYPE ty_s_ex_tabcell VALUE IS INITIAL. "Overname van de gegevens l_cell-row = x_tabix. l_cell-col = x_col. l_pos = x_pos. l_string = xy_line. "Er bestaan mogelijk cellen met scheidingsteken erin "Bijvoorbeeld: --> ;"abc;def"; IF ( x_sep EQ ',' OR x_sep EQ ';' ) AND l_string(1) EQ wildcard. "Omgaan met separator convert_line2cell_with_sep( EXPORTING x_sep = x_sep CHANGING xy_value = l_cell-value xy_string = l_string xy_pos = l_pos ). ELSE. "Cel waarde direct overnemen IF l_pos GT 0. l_cell-value = xy_line(l_pos). ENDIF. ENDIF. "Cel waarde opslaan en variabelen afwerken IF l_pos GT 0. APPEND l_cell TO xy_cells. ENDIF. l_pos = l_pos + 1. xy_line = xy_line+l_pos. ENDMETHOD.
Nu hebben we nog een bijzondere mogelijkheid. Het is namelijk mogelijk, dat de cellen van MS Excel het scheidingsteken bevatten in de tekst. Die moeten we verwijderen, willen we de kolommen intact laten. Daarvoor is de methode CONVERT_LINE2CELL_WITH_SEP aan te maken met de volgende interface.
Blad 19
En de ABAP code. METHOD convert_line2cell_with_sep. DATA: l_pos TYPE i, l_cellend TYPE c LENGTH 2. FIELD-SYMBOLS: TYPE any. "Einde van de cel bevat wildcard teken met scheidingsteken "De laatste cel bevat aan het einde alleen de wildcard l_cellend = wildcard. l_cellend+1 = x_sep. IF xy_string CS wildcard. xy_string = xy_string+1. IF xy_string CS l_cellend. "Niet laatste cel l_pos = sy-fdpos. ASSIGN xy_string(l_pos) TO . xy_value = . l_pos = l_pos + 2. xy_pos = l_pos. xy_string = xy_string+l_pos. ELSEIF xy_string CS wildcard. "Laatste cel l_pos = sy-fdpos. ASSIGN xy_string(l_pos) TO . xy_value = . l_pos = l_pos + 1. xy_pos = l_pos. xy_string = xy_string+l_pos. ENDIF. ENDIF. ENDMETHOD.
Dan komen we nu toe aan de methode, die het export formaat gaat opbouwen. Net als alle voorgaande methoden (behalve de constuctors) is ook deze methode privé (dus niet publiek toegankelijk. De methode CONVERT_TABLE_FORUSAGE heeft geen interface maar wel ABAP code.
Blad 20
METHOD convert_table_forusage. DATA: target TYPE string, init_col TYPE kcd_ex_col_n, prev_col TYPE kcd_ex_col_n. FIELD-SYMBOLS: TYPE ty_s_ex_tabcell, TYPE ty_c_4096. CLEAR ms_imported[]. LOOP AT ms_celldata ASSIGNING . "Bepaal aantal scheidingstekens voor elke lege kolom. "Als een kolom leeg is worden 2 nieuwe scheidingstekens toegevoegd. init_col = -col - prev_col. DO init_col TIMES. CONCATENATE target delimiter INTO target IN CHARACTER MODE. ENDDO. prev_col = -col. AT NEW row. CLEAR target. ENDAT. "Voorkom cellen met het scheidingsteken erin. "Vervang deze door een punt. IF -value CA delimiter. REPLACE ALL OCCURRENCES OF delimiter IN -value WITH '.' IN CHARACTER MODE. ENDIF. "Samenvoegen in de regel CONCATENATE target -value INTO target IN CHARACTER MODE. CONDENSE target. "Aan het einde van de cellen van dezelfdce regel slaan we de regel op AT END OF row. APPEND INITIAL LINE TO ms_imported ASSIGNING . = target. "Vorige kolom reset prev_col = 0. ENDAT. ENDLOOP. ENDMETHOD.
En dan komen we nu toe aan de enige publieke methode. De methode MS_EXCEL_FILE_IMPORT is de methode, die u zult oproepen om een MS Excel bestand te importeren. Deze methode kent de volgende interface.
Blad 21
En de laatste ABAP code in dit object. METHOD ms_excel_file_import. "Importeren van MS Excel bestand (in object) ms_excel_import_data( EXPORTING separator = cl_abap_char_utilities=>horizontal_tab CHANGING bestandsnaam = bestandsnaam EXCEPTIONS upload_ole = 1 OTHERS = 2 ). IF sy-subrc NE 0. CLEAR sy-subrc. ENDIF. "De cel data omzetten in een regeltabel (in object) convert_table_forusage( ). "MS Excel data cellen in een regel gescheiden door "het pipe-teken "|". exceldata = ms_imported. ENDMETHOD.
Hiermee is ons object compleet. Het object kan worden gecompileerd en geactiveerd.
Blad 22
Voorbeeld verwerking MS Excel import Natuurlijk is een voorbeeld over hoe we de individuele cellen kunnen benaderen op zijn plaats. Hiervoor heb ik een tijdelijk rapport geschreven. *&---------------------------------------------------------------------* *& Report ZZ_VNSG_TIP_TEST * *&---------------------------------------------------------------------* REPORT zz_vnsg_tip_test. TYPES: ty_c_132 ty_c_4096 TYPES: ty_t_veld ty_t_excel DATA: file velden excel obj
TYPE c LENGTH 132, TYPE c LENGTH 4096. TYPE STANDARD TABLE OF ty_c_132, TYPE STANDARD TABLE OF ty_c_4096.
TYPE TYPE TYPE TYPE
string, ty_t_veld, ty_t_excel, REF TO zcl_excel.
FIELD-SYMBOLS: TYPE ty_c_4096, TYPE ty_c_132. START-OF-SELECTION. obj = zcl_excel=>instance. obj->ms_excel_file_import( CHANGING bestandsnaam = file exceldata = excel ). END-OF-SELECTION. LOOP AT excel ASSIGNING . CLEAR velden[]. SPLIT AT '|' INTO TABLE velden IN CHARACTER MODE. LOOP AT velden ASSIGNING . "Hier kunt u de inhoud bekijken, converteren "of aan uw eigen structuur toevoegen. "De waarde van SY-TABIX geeft de kolom weer. CONTINUE. ENDLOOP. ENDLOOP. MESSAGE s011(pc) WITH file.
Blad 23
Tot slot De export is specifiek op de XML wijze gedaan, voor gebruik in de WebUI van CRM. De import is op de ABAP wijze uitgevoerd. Natuurlijk kan dat ook andersom, maar dat laat ik graag aan u zelf over. De export is in een aparte BSP applicatie gebouwd en kan in elke andere BSP worden opgenomen. Door wat code toe te voegen voor een bestandsnaam en uw interne data mee te geven (in plaats van hard gecodeerd) kunt u de export eenvoudig gebruiken door het aansturen van de DO_REQUEST methode. De import is een al bestaande functionaliteit op SAP ECC systemen. Ik heb echter hier de ABAP OO methode een klein beetje gevolgd. In ieder geval wens ik jullie succes met het verder uitbreiden van de mogelijkheden.
Deze tip is aangeleverd door Superp Technology Consultants BV (http://www.superp.nl/). Voor vragen of extra informatie over dit onderwerp kunt u via email contact opnemen met Robbie Veenstra (mailto:[email protected]).
Blad 24
| | | | | | | | | | | | | | | | | | |