ABAP, XML, XSLT and something about acquisition of web services in SAP

Long time no written I know… The last couple of months were a bit busy so I guess I owe my blog some more attention… Just noticed that there are maybe three draft posts waiting for approval:  one for the Digra conference that I visited in September (more on: DIGRA2011  and I was a speaker there about the games that I have made for motivating physical activity: Me,  but the folks were even cooler than I could imagine so they really deserve a post), one kind of a review of my new smartphone HTC Desire S (the device: HTC Desire S) and one about ABAP & JSON project that will be the only one that will see the the light of the day as soon as I finish it 😀

I promise this 2012 I will write more often and I guess someone will find what they need in the posts.

As a first 2012 post I  chose to write something about SAP and web service acquisition. This is a really simple example with simple code but it can be further extended and improved in different cases.

I would suppose that the reader is familiar with XML and XSLT (if not please check the following basic tutorials: W3Schools ) and has experience in any programming language and thus will easily “read” and understand the ABAP lines of code. Maybe he/she has also tried some web service acquisition in some other language but is an ABAP beginner and wants to get some job done really quickly.

So.. we have some web-service  from the National Bank of Republic of Macedoniacurrency download – for getting the currency exchange rates on a given date. This is one of the main things that is implemented in any project since any company needs the exchange rates in many of the processes. Since I am not here to write about business processes I will stick to the technical details.

So what one has to do first is to see what are the input parameters and what is the result from the web service. Let’s take the method GetExchangeRates as an example the input parameters are the start and end date for which we need the rates and the result is a string. When the answer is encapsulated in a string it requires some testing to get the full information about the response. I use soapUI to test the methods and analyze the answers and for this method I got something like:

<GetExchangeRateResult><![CDATA[<dsKurs>
  <xs:schema id="dsKurs" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="dsKurs" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="KursZbir">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="RBr" type="xs:double" minOccurs="0" />
                <xs:element name="Datum" type="xs:dateTime" minOccurs="0" />
                <xs:element name="Valuta" type="xs:double" minOccurs="0" />
                <xs:element name="Oznaka" type="xs:string" minOccurs="0" />
                <xs:element name="Drzava" type="xs:string" minOccurs="0" />
                <xs:element name="Nomin" type="xs:double" minOccurs="0" />
                <xs:element name="Sreden" type="xs:double" minOccurs="0" />
                <xs:element name="DrzavaAng" type="xs:string" minOccurs="0" />
                <xs:element name="NazivMak" type="xs:string" minOccurs="0" />
                <xs:element name="NazivAng" type="xs:string" minOccurs="0" />
                <xs:element name="Datum_f" type="xs:dateTime" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>978</Valuta>
    <Oznaka>EUR</Oznaka>
    <Drzava>ЕМУ</Drzava>
    <Nomin>1</Nomin>
    <Sreden>61.5044</Sreden>
    <DrzavaAng>EMU</DrzavaAng>
    <NazivMak>евро</NazivMak>
    <NazivAng>Euro</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>840</Valuta>
    <Oznaka>USD</Oznaka>
    <Drzava>С А Д</Drzava>
    <Nomin>1</Nomin>
    <Sreden>48.2918</Sreden>
    <DrzavaAng>USA</DrzavaAng>
    <NazivMak>САД долар</NazivMak>
    <NazivAng>US dollar</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>826</Valuta>
    <Oznaka>GBP</Oznaka>
    <Drzava>В.Британија</Drzava>
    <Nomin>1</Nomin>
    <Sreden>74.0526</Sreden>
    <DrzavaAng>U.K.</DrzavaAng>
    <NazivMak>британска фунта</NazivMak>
    <NazivAng>British pound</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>756</Valuta>
    <Oznaka>CHF</Oznaka>
    <Drzava>Швајцарија</Drzava>
    <Nomin>1</Nomin>
    <Sreden>50.7797</Sreden>
    <DrzavaAng>Switzerland</DrzavaAng>
    <NazivMak>швајцарски франк</NazivMak>
    <NazivAng>Swiss franc</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>752</Valuta>
    <Oznaka>SEK</Oznaka>
    <Drzava>Шведска</Drzava>
    <Nomin>1</Nomin>
    <Sreden>6.9485</Sreden>
    <DrzavaAng>Sweden</DrzavaAng>
    <NazivMak>шведска круна</NazivMak>
    <NazivAng>Swedish krona</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>578</Valuta>
    <Oznaka>NOK</Oznaka>
    <Drzava>Норвешка</Drzava>
    <Nomin>1</Nomin>
    <Sreden>8.0115</Sreden>
    <DrzavaAng>Norway</DrzavaAng>
    <NazivMak>норвешка круна</NazivMak>
    <NazivAng>Norwegian krone</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>392</Valuta>
    <Oznaka>JPY</Oznaka>
    <Drzava>Јапонија</Drzava>
    <Nomin>100</Nomin>
    <Sreden>62.8109</Sreden>
    <DrzavaAng>Japan</DrzavaAng>
    <NazivMak>јапонски јен</NazivMak>
    <NazivAng>Japanese yen</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>208</Valuta>
    <Oznaka>DKK</Oznaka>
    <Drzava>Данска</Drzava>
    <Nomin>1</Nomin>
    <Sreden>8.2705</Sreden>
    <DrzavaAng>Denmark</DrzavaAng>
    <NazivMak>данска круна</NazivMak>
    <NazivAng>Danish krone</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>124</Valuta>
    <Oznaka>CAD</Oznaka>
    <Drzava>Канада</Drzava>
    <Nomin>1</Nomin>
    <Sreden>47.5084</Sreden>
    <DrzavaAng>Canada</DrzavaAng>
    <NazivMak>канадски долар</NazivMak>
    <NazivAng>Canadian dollar</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>
  <KursZbir>
    <RBr>7</RBr>
    <Datum>2012-01-13T00:00:00+01:00</Datum>
    <Valuta>36</Valuta>
    <Oznaka>AUD</Oznaka>
    <Drzava>Австралија</Drzava>
    <Nomin>1</Nomin>
    <Sreden>49.9914</Sreden>
    <DrzavaAng>Australia</DrzavaAng>
    <NazivMak>австралиски долар</NazivMak>
    <NazivAng>Australian dollar</NazivAng>
    <Datum_f>2012-01-12T00:00:00+01:00</Datum_f>
  </KursZbir>

Aha there is the definition: KursZbir is the element containing all the data about the exchange rate of the currency according the Macedonian denar. And that is the content we need to put in an ABAP table and do what is necessary with it.

So before you think about which parsing technique should be used and all that I will tell you that the solution is just couple of clicks away. SAP is really sometimes nice to developers and sometimes it is better to search for a day or two first for some technique or a module instead of writing a bunch of code.

Next please go through the following tutorial about how to set up a proxy and test it on the following link. It contains detailed explanation with screens how to create a Proxy class, set up URL and create valid SOAP message and all with couple of clicks no line of code. 🙂 This is not the only one available on the internet you can find many more…

You see here that the method is really simple and the result is just square root of the value sent. The problem is when there is a more complex structure like the one we have to deal with now. Now we have to make a transformation. It is nothing too complicated just a way to tell one really great SAP function how to transform the “weird” XML data string into table data. It is done through the Object Navigator (SE80) . Open the menu: Workbench -> Edit Object. From the dialog select transformation and then create.

For this example the following XSL transformation was used: (i put it here so that you can easily copy and paste )

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sap="http://www.sap.com/sapxsl" version="1.0">
  <xsl:strip-space elements="*"/>
  <xsl:template match="/">
    <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
      <asx:values>
        <ALL_KURS>
          <xsl:apply-templates select="//KursZbir"/>
        </ALL_KURS>
      </asx:values>
    </asx:abap>
  </xsl:template>
  <xsl:template match="KursZbir">
  <ALLKURS>
    <RBR>
      <xsl:value-of select="RBr"/>
    </RBR>
    <DATUM>
      <xsl:value-of select="Datum"/>
    </DATUM>
    <VALUTA>
      <xsl:value-of select="Valuta"/>
    </VALUTA>
    <OZNAKA>
      <xsl:value-of select="Oznaka"/>
    </OZNAKA>
    <DRZAVA>
      <xsl:value-of select="Drzava"/>
    </DRZAVA>
    <NOMIN>
      <xsl:value-of select="Nomin"/>
    </NOMIN>
    <SREDEN>
      <xsl:value-of select="Sreden"/>
    </SREDEN>
    <DRZAVAANG>
      <xsl:value-of select="DrzavaAng"/>
    </DRZAVAANG>
    <NAZIVMAK>
      <xsl:value-of select="NazivMak"/>
    </NAZIVMAK>
    <NAZIVANG>
      <xsl:value-of select="NazivAng"/>
    </NAZIVANG>
    <DATUM_F>
      <xsl:value-of select="Datum_f"/>
    </DATUM_F>
 </ALLKURS>
  </xsl:template>
</xsl:transform>

Actually writing the transformation is the hard part. The ABAP code will actually be short and simple.

Here it goes:

*&---------------------------------------------------------------------*
*& Report  Z_KURS_DOWNLOAD
*&---------------------------------------------------------------------*
 REPORT  z_kurs_download.
 DATA: proxy TYPE REF TO zkurstestco_kurs_soap .
 DATA : st_data TYPE start_date ,
        en_data TYPE end_date.
 data: cr_date type string.
 concatenate sy-datum+6(2) '.' sy-datum+4(2) '.' sy-datum(4) into cr_date.

 DATA: zinput TYPE zkurstestget_exchange_rate_so1,
       zoutput TYPE zkurstestget_exchange_rate_soa.
 DATA: result TYPE string.

 TYPES : BEGIN OF kurszbir,
       rbr TYPE string,
       datum TYPE string,
       valuta TYPE string,
       oznaka TYPE string,
       drzava TYPE string,
       nomin TYPE string,
       sreden TYPE string,
       drzavaang TYPE string,
       nazivmak TYPE string,
       nazivang TYPE string,
       datum_f TYPE string ,
 END OF kurszbir.

 DATA itab TYPE kurszbir OCCURS 0.
 DATA lt_kurs TYPE TABLE OF kurszbir.
 DATA wa_kurs TYPE TABLE OF kurszbir WITH HEADER LINE.

 TRY.
     CREATE OBJECT proxy
       EXPORTING
         logical_port_name = 'ZKURSTESTCO_KURS_SOAP_PORT'.
   CATCH cx_ai_system_fault .
 ENDTRY.

 * ADD SYSTEM DATE IN FORMAT DD.MM.YYYY
 zinput-start_date = cr_date.
 zinput-end_date = cr_date. "cr_date .

 TRY.
     CALL METHOD proxy->get_exchange_rate
       EXPORTING
         input  = zinput
       IMPORTING
         output = zoutput.
   CATCH cx_ai_system_fault .
   CATCH cx_ai_application_fault .
 ENDTRY.

 result = zoutput-GET_EXCHANGE_RATE_RESULT.
 REPLACE ALL OCCURRENCES OF '##' IN result WITH ' ' .

 TRY.
     CALL TRANSFORMATION Z_KURS_XSLT
             SOURCE XML result
             RESULT     all_kurs = lt_kurs.
   CATCH cx_ai_system_fault.
 ENDTRY.

 MOVE lt_kurs TO wa_kurs[]. 

 LOOP AT wa_kurs .
   write: / wa_kurs-datum, ' ', wa_kurs-valuta, ' ',
  wa_kurs-nomin, ' ', wa_kurs-sreden, ' ', wa_kurs-drzavaang, ' ',    wa_kurs-nazivmak, ' '.
 ENDLOOP.

The output of the program is the following:

After that you can either schedule a job or set a transaction and the client can perform it on their own.

I guess someone will find this example useful and the good thing is that it is actually possible to test it because banks are generally reliable for this kind of data 🙂

Next time maybe something more about more complex XML structures.

Advertisements

2 Responses to ABAP, XML, XSLT and something about acquisition of web services in SAP

  1. Hello Ilina,

    Nicely explained the integration of ABAP and XML using the Transformations.

    Regards,
    Naimesh Patel

    • karevask says:

      Thanks for the nice words!
      It feels good when a more experienced member of the community appreciates!
      I will try to “live” up to the standards 🙂

      Regards,
      Ilina

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: