Skip to Content
Technical Articles
Author's profile photo Sandra Rossi

ST Transformations: XML 2 ABAP, a working example

I decided to write this post after reading the blog post “XSLT Transformations: XML 2 ABAP, a working example” from Joris Bots, which I found very interesting because it’s simple and with an example which works anywhere.

But the transformation was proposed in XSLT, not in ST (“Simple Transformation“, a SAP proprietary language), which has a better performance over XSLT (measured it a long time ago, for a very simple transformation, it was approximately 10 X faster).

In this post, I used the same titles and example than Joris used in his post (thanks for authorizing me), so that the visitors can go quickly from ST to XSLT and vice versa by switching between the 2 posts.

Note: this post is not about the differences between XSLT and ST, it’s just a little example for quickly understanding the general structure of a Simple Transformation.

 

 

The XML

(same as the one in the other blog post)

<?xml version="1.0" encoding="UTF-8"?>
<File>
	<Head>
		<Name>K. Richards</Name>
	</Head>
	<Items>
		<ITM QTY="23" EAN="123123123123" CAT="BL"/>
		<ITM QTY="100" EAN="123123123123" CAT=""/>
		<ITM QTY="240" EAN="123123123123" CAT=""/>
		<ITM QTY="989" EAN="123123123123" CAT=""/>
		<ITM QTY="1000" EAN="123123123123" CAT=""/>
		<ITM QTY="5" EAN="123123123123" CAT="BL"/>
		<ITM QTY="50" SOH="4000299949" EAN="123123123123" SOI="000010" CAT=""/>
		<ITM QTY="140" EAN="123123123123" CAT=""/>
		<ITM QTY="420" EAN="123123123123" CAT="QI"/>
		<ITM QTY="30" EAN="123123123123" CAT=""/>
		<ITM QTY="20" EAN="123123123123" CAT="QI"/>
		<ITM QTY="475" SOH="4000299949" EAN="123123123123" SOI="000040" CAT=""/>
		<ITM QTY="300" EAN="123123123123" CAT=""/>
		<ITM QTY="994" EAN="123123123123" CAT=""/>
		<ITM QTY="24" EAN="123123123123" CAT="BL"/>
		<ITM QTY="3" EAN="123123123123" CAT="BL"/>
		<ITM QTY="441" EAN="123123123123" CAT=""/>
		<ITM QTY="240" EAN="123123123123" CAT="QI"/>
		<ITM QTY="5" EAN="123123123123" CAT=""/>
		<ITM QTY="102" EAN="123123123123" CAT="BL"/>
		<ITM QTY="2" EAN="123123123123" CAT=""/>
		<ITM QTY="360" EAN="123123123123" CAT="QI"/>
		<ITM QTY="403" EAN="123123123123" CAT=""/>
		<ITM QTY="425" SOH="123123123123" EAN="6941023243415" SOI="000030" CAT=""/>
		<ITM QTY="100" EAN="123123123123" CAT=""/>
		<ITM QTY="220" EAN="123123123123" CAT=""/>
		<ITM QTY="1000" EAN="123123123123" CAT=""/>
		<ITM QTY="25" SOH="4000299949" EAN="123123123123" SOI="000020" CAT="BL"/>
		<ITM QTY="425" SOH="4000299949" EAN="123123123123" SOI="000020" CAT=""/>
		<ITM QTY="340" EAN="123123123123" CAT=""/>
		<ITM QTY="1" EAN="123123123123" CAT="BL"/>
	</Items>
</File>

 

 

The ST

Code of the ST transformation (transaction STRANS – or directly inside Eclipse ADT):

<?sap.transform simple?>
<tt:transform xmlns:tt="http://www.sap.com/transformation-templates">

  <tt:root name="FILE"/>

  <tt:template>
    <File tt:ref=".FILE"> <!--FILE Needs to match name of RESULT variable in CALL TRANSFORMATION call-->
      <Head tt:ref="HEAD">
        <Name tt:value-ref="NAME"/>
      </Head>
      <Items>
        <tt:loop ref="ITEMS">
          <ITM>
            <tt:group>
              <tt:cond frq="?"><tt:attribute name="QTY" value-ref="QTY"/></tt:cond>
              <tt:cond frq="?"><tt:attribute name="SOH" value-ref="SOH"/></tt:cond>
              <tt:cond frq="?"><tt:attribute name="EAN" value-ref="EAN"/></tt:cond>
              <tt:cond frq="?"><tt:attribute name="SOI" value-ref="SOI"/></tt:cond>
              <tt:cond frq="?"><tt:attribute name="CAT" value-ref="CAT"/></tt:cond>
            </tt:group>
          </ITM>
        </tt:loop>
      </Items>
    </File>
  </tt:template>

</tt:transform>

 

 

The ABAP

(almost the same as in the other post, except that I preferred to output the result into a structured variable instead of an internal table, to correspond better to the input XML)

REPORT.

TYPES: BEGIN OF lty_items,
         qty TYPE string,
         soh TYPE string,
         ean TYPE string,
         soi TYPE string,
         cat TYPE string,
       END OF lty_items.

TYPES: BEGIN OF lty_head,
         name TYPE string,
       END OF lty_head.

TYPES: BEGIN OF lty_out,
         head  TYPE lty_head,
         items TYPE STANDARD TABLE OF lty_items WITH DEFAULT KEY,
       END OF lty_out.

DATA: lv_xml TYPE string,
      lt_xml TYPE STANDARD TABLE OF string,
      ls_out TYPE lty_out.

PARAMETERS p_file TYPE string LOWER CASE DEFAULT 'C:\link\to\test.xml'.

"Load xml file
cl_gui_frontend_services=>gui_upload(
  EXPORTING
    filename = p_file
    filetype = 'ASC'
  CHANGING
    data_tab = lt_xml
  EXCEPTIONS
    OTHERS   = 19 ).

lv_xml = concat_lines_of( lt_xml ).

CALL TRANSFORMATION zmy_xslt_2
  SOURCE XML lv_xml
  RESULT file = ls_out.
cl_demo_output=>new( )->write_data( ls_out-head
                     )->write_data( ls_out-items )->display( ).

 

 

The result

(running the ABAP program -> contents of variable LS_OUT)

 

 

Now for some pointers

Here are some important tips

  1. ST has a syntax which usually allows the same transformation being called in both directions, from XML to ABAP, but also from ABAP to XML. It’s a great feature, but it also complicates the ST syntax, even if you want to use the transformation only in one direction, especially for optional elements (for instance, tt:group and tt:cond frq=”?” altogether allow the attributes to be optional and in any position)
  2. ST is not able to convert from XML to XML (XSLT can do it), but “thanks to that” ST doesn’t require to declare the asXML elements (<asx:abap…; they are required only when you write an XSLT transformation for transforming from or to ABAP).
  3. Whatever the direction is, the transformation is always to be written with the XML elements as being elements in the transformation (<element …>), and ABAP component names as being in value-ref and ref attributes (you can see what I mean by comparing the ST and XSLT transformations, they are different although the XSLT writes in the same direction i.e. XML to ABAP).
  4. Always respect the case of XML words, it’s very important in all XML languages!

And don’t forget to refer to the Simple Transformation documentation (and its too few examples).

Assigned Tags

      4 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Shai Sinai
      Shai Sinai

      Thanks for this nice example.

      That made we wonder: What is the XSLT equivalent (if any) for deserialization of elements in any order (i.e. without a fixed order), like with tt:group?

      Author's profile photo Sandra Rossi
      Sandra Rossi
      Blog Post Author

      In the past, when I did some complex XSLT, I didn't need an equivalent statement, so I guess there's no need because XSLT is a one-way transformation: you define the target XML element or attribute (fixed order), that you fill with the source element by an XPath expression, no need of giving its exact position.

      Author's profile photo Patrick Steffens
      Patrick Steffens

      That's actually a very nice, minimal and comprehensive tutorial. Thanks a lot for that.

      What would I need to change if <Items> had an attribute? E.g. <items guid="abc">?

      In the ST, I would need to add an attribute tag below <Items guid="abc">, I guess. But how would I reflect it in the ABAP types and how would this change affext the ST code?

      I spent more than three hours figuring that out and would greatly appreciate I you could clarify on that.

      Thank you 🙂

      Best
      Patrick

      Author's profile photo Sandra Rossi
      Sandra Rossi
      Blog Post Author

      Yes, ST is a little bit more complex than XSLT!

      XML:

      	</Head>
      	<Items guid="abc">    <!--        <======= New attribute "guid" -->
      		<ITM QTY="23" EAN="123123123123" CAT="BL"/>
      

      If "guid" is the only and mandatory attribute, that you want to both serialize and deserialize, then the ST will be like this:

            <Items>
              <tt:attribute name="guid" value-ref="ITEMS_GUID"/>  <!-- <====== Line added -->
              <tt:loop ref="ITEMS">

      ABAP code:

      TYPES: BEGIN OF lty_out,
               head       TYPE lty_head,
               items_guid TYPE string,  " <=== add this line
               items      TYPE STANDARD TABLE OF lty_items WITH DEFAULT KEY,
             END OF lty_out.