1 VNSG magazine 2014 ABAP - Office documenten en met name Excel sheets vormen een algemeen middel om data in SAP systemen te krijgen, of er uit te rapporteren. Al eeuwen biedt SAP mogelijkhedenheden om met OLE vanuit SAP te communiceren met MS-Office. In de SCN community zijn ABAP2XLSX en XLSX2ABAP libraries gepubliceerd. In de 7.02 nw releases van SAP zit echter standaard een API om te integreren met Excel, Word en Powerpoint. In deze tip een korte introductie. We richten ons om het behapbaar te houden uitsluitend op Excel import met behulp van de SAP class CL_OPENXML_PACKAGE. XLSx, PPTx, DOCx, zijn ZIP bestanden Uitgangspunt van dit document is dat we de te lezen Excel sheet in binaire form hebben. Of dat nu met een upload, als payload in een bericht, als attachment in een mail of wat dan ook binnenkomt. Van belang is nu om te weten dat een XLSx bestandje eigenlijk een ZIP file is. We nemen bijvoorbeeld het volgende XLSx bestandje VNSG.xlsx, met daarin één sheet: Zes cellen dus, A1, A2 en A3 met de waarde van 1, 2 resp 3, en B1, B2 en B3 met de (string!) waarde 1, 2 en 3. Hernoemen we de extensie van het bestand dat we hebben opgeslagen van *.xlsx naar *.zip, dan ziet het er als we het openen met ZIP (of als je het parset in Java, of wat dan ook) als volgt uit:
2 VNSG magazine 2014 Als we het simpel houden (kan altijd complexer) zitten de voor ons interessante gegevens in de bestanden /xl/worksheets/sheet1.xml: en xl/sharedstrings.xml... Concreet: we vinden in worksheets\sheet1.xml elementen met naam row/c met attribute r="<cellid>" terug. Als attribute "s" van dit element gelijk is aan "1" dan betekent dit een verwijzing naar element volgnummer(row/c/v) in xl/sharedstrings (nb! element 0 is het eerste voorkomen van...). Daar kunnen we dus wat mee als we inkomende XLSx bestanden ontzippen en de waarde op deze wijze uitlezen.
3 VNSG magazine 2014 Voor we verder gaan even een proof of concept voor DOCx bestanden. Bronbestand is HelloWord.docx (vindt FOO lekker): Is als ZIP gelezen: Lezen we word/document.xml Dan toont dat dus hetzelfde concept...
4 VNSG magazine 2014 Verwerking in ABAP Uitgangspunt hebben we al genoteerd, namelijk een binary xstring (iv_excel in code hieronder) met de gehele XLSx. De basis begint nu met de factory cl_xlsx_document=>load_package( <xstring> ), die een object teruggeeft van het type CL_OPENXML_PACKAGE. data objxlsx type ref to CL_OPENXML_PACKAGE. objxlsx = cl_xlsx_document=>load_package( iv_excel ). objxlsx is een object met een iterator die de parts teruggeeft, en die parts zijn inderdaad de files die we al eerder terugzagen bij het openen van de zipfile. data lr_part type ref to cl_openxml_part. data lr_parts type ref to cl_openxml_partcollection, data lv_partcount type i. lr_parts = objxlsx->get_parts( ). lv_partcount = lr_parts->get_count( ). lv_partcount = lr_workbook->get_parts( )->get_count( ). do lv_partcount times. sv_index = sy-index - 1. lv_uri = lr_workbook->get_parts( )->get_part( sv_index )-> get_uri( )->get_uri( ). lv_uri is nu een string die het pad naar het bestand geeft. Er waren er meerdere, maar we waren vooralsnog alleen geïnteresseerd in '/xl/sharedstrings.xml' en '/xl/worksheets/sheet1.xml'. Daar moeten we door te loopen over de iterator de index van bepalen, en dan kunnen we ze lezen. xxmlsheet1 = lr_workbook->get_parts( )->get_part( <gevondenindex> ) ->get_data( ). xxmlsharedst = lr_workbook->get_parts( )->get_part( <gevondenindex> ) ->get_data( ). xxmlsheet1 en xxmlsharedst zijn hierbij xstrings die we kunnen parsen met de ixml classes. Zonder hier vervelend te willen worden in volledigheid (het is een tip, geen werkinstructie) een snippet voor het lezen van de shared string XML: lr_ixml = cl_ixml=>create( ). lr_ixml_document = lr_ixml->create_document( ). lr_ixml_stream_factory = lr_ixml->create_stream_factory( ). lr_ixml_istream = lr_ixml_stream_factory ->create_istream_xstring( xxmlsharedst ). lr_ixml_parser = lr_ixml->create_parser( document = lr_ixml_document istream = lr_ixml_istream stream_factory = lr_ixml_stream_factory ).
5 VNSG magazine 2014 lr_ixml_parser->parse( ). lr_ixml_istream->close( ). if lr_ixml_node_sst is bound. lr_ixml_node_silist = lr_ixml_node_sst->get_children( ). if lr_ixml_node_silist is bound. lv_nrof_sinodes = lr_ixml_node_silist->get_length( ). do lv_nrof_sinodes times. lv_sstidx = sy-index - 1. try. lv_value = lr_ixml_node_silist->get_item( lv_sstidx ) -get_first_child( )->get_value( ). // There it is!! catch cx_root. // any endtry. enddo. endif. endif. Voor de worksheet zelf is het van hetzelfde laken, maar vergeet niet de waarde te vervangen door de gevonden sharedstring (als er een attribuut 's' was...)! Finally Het voorbeeld heb ik teasing en simpel gehouden, maar kan natuurlijk zo complex worden als je zelf wil. En zijn de ABAP2XLSX/XLSX2ABAP libraries hiermee nu overbodig geworden? Het antwoord daarop is dat die een compleet framework bieden, en bijvoorbeeld ook een uitgewerkt concept van styles ondersteunen. Dat kan je natuurlijk zelf gaan maken (kost tijd), en het leren (lees: doorgronden) van een library vergt ook tijd. Het charmante van de CL_OPENXML_PACKAGE is echter de uniformiteit van de oplossing, en de wijze waarop dat een maatwerkoplossing ondersteunt. Ik zou echter niet meer met OLE koppelingen aan de slag gaan. Al was het alleen maar om de specifieke ondersteuning van de SAPGUI die dat vereist. Hans Gmelig Meyling, September 2014 Literatuur, links en notes ABAP2XLSX library van Ivan Femia: SCN Startpage: http://wiki.scn.sap.com/wiki/display/abap/abap2xlsx GitHub: https://github.com/ivanfemia/abap2xlsx SCN blog van Benu Mariantony SCN: http://scn.sap.com/docs/doc-33578