Technical Articles
XSLT Transformations: XML 2 ABAP, a working example with deep structures
I consistently run into trouble when using XSLT Transformation to import XML data into (deep) ABAP Structures. Partly because I do not use it often I guess. So to make sure that next time I will quickly find a how-to that works for me I created this blog 😉
Other options are; to use Simple Transformation or the standard Identity Transformation (XSLT via existing transformation ‘ID’).
The goal now is to import the following XML into a deep ABAP structure using XSLT
The XML
<?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 XSLT
The import can be achieved with the below XSL Transformation (Transaction STRANS)
<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>
<FILE> <!--FILE Needs to match name of RESULT variable in CALL TRANSFORMATION call-->
<xsl:for-each select="/File">
<!-- <DUMMY1> = Dummy, not in ABAP structure-->
<DUMMY1>
<HEAD>
<NAME>
<xsl:value-of select="Head/Name"/>
</NAME>
</HEAD>
<ITEMS>
<xsl:for-each select="Items/ITM">
<DUMMY2>
<!-- <DUMMY2> = Dummy, not in ABAP structure-->
<QTY>
<!-- @ = Attribute of element rather than element-->
<xsl:value-of select="@QTY"/>
</QTY>
<SOH>
<xsl:value-of select="@SOH"/>
</SOH>
<EAN>
<xsl:value-of select="@EAN"/>
</EAN>
<SOI>
<xsl:value-of select="@SOI"/>
</SOI>
<CAT>
<xsl:value-of select="@CAT"/>
</CAT>
</DUMMY2>
</xsl:for-each>
</ITEMS>
</DUMMY1>
</xsl:for-each>
</FILE>
</asx:values>
</asx:abap>
</xsl:template>
</xsl:transform>
The ABAP
And here is the ABAP Report that calls the transformation
REPORT zjbo_xslt_2.
TYPES BEGIN OF lty_items.
TYPES qty TYPE string.
TYPES soh TYPE string.
TYPES ean TYPE string.
TYPES soi TYPE string.
TYPES cat TYPE string.
TYPES END OF lty_items.
TYPES BEGIN OF lty_head.
TYPES name TYPE string.
TYPES END OF lty_head.
TYPES BEGIN OF lty_out.
TYPES head TYPE lty_head.
TYPES items TYPE STANDARD TABLE OF lty_items WITH DEFAULT KEY.
TYPES END OF lty_out.
DATA lv_xml TYPE string..
DATA lt_xml TYPE STANDARD TABLE OF string.
DATA ls_out TYPE lty_out.
DATA lt_out TYPE STANDARD TABLE OF lty_out.
PARAMETERS p_file TYPE string 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 = lt_out.
cl_demo_output=>new( )->write_data( lt_out[ 1 ]-head
)->write_data( lt_out[ 1 ]-items )->display( ).
Now for some pointers
Here are some important tips
- The RESULT variable of the CALL TRANSFORMATION must have the same name as the root target element in the XSLT (in this example; ‘file’ == <FILE>
- The target elements in the XSLT (ie the elemenst that correspond with your target ABAP structure) must be in CAPITALS; Like <HEAD>, <NAME>, …
- The Source element references must be in same case as in the XML. Like “/Items/ITM”
- The output of the CALL TRANSFORMATION must be a table type (structure is not allowed, other outputs like XML and ref to data is also possible, for that see SAP Help). Like in our example; lt_out is a table type.
- Each substructure or table line in the output needs to be explicitly defined with a dummy structure name. These dummy structure names do not exist in the ABAP target, but need to be defined. The name used is irrelevant. See <DUMMY1> and <DUMMY2> in XSLT
UPDATE July 2019:
Sandra Rossi wrote a follow up using ST Transformation instead of XSLT; https://blogs.sap.com/2019/07/02/st-transformations-xml-2-abap-a-working-example/
Joris Bots
Thanks for posting. For clarity I'd suggest to update the title to note that this is related specifically to the deep structures. Otherwise the title is confusing.
Ha, lifesaver! Thanks a bunch.
Hi, I’d like to write the same post as yours but adapted to the ST language, do you authorize me to plagiarize your XML and ABAP example, the general structure and your titles? This way, it will be easy for visitors to go from one post to the other. I will include a reference to your post of course. Thanks!
Note about the output of CALL TRANSFORMATION: it’s not required to output to an internal table, one may use a structure, a simple variable and so on. In your case, it’s just that you wrote your XSLT such a way that an internal table is required. If you remove the elements <xsl:for-each…><DUMMY1>, then you may transform to the structure LS_OUT.
By the way, there’s a little syntax error around <!– in the XSLT:
to be changed into:
Sandra,
Thanks for the remarks, syntax error is probably due to MS word which I used as an intermediate tool. And sure, go ahead an use my sample in your posts.
Best regards,
Joris
Here is the blog post about ST
Transformations... always a mess because of not doing it often enough:-)
Hello,
This is a really helpful post.
I am new to transformation and was following your example to deserialize an XML structure into an ABAP table, but I am unable to get any results.
Could you please help me on how we could extract the results from the following structure ?
<File>
<Items>
<results>
<id>TEST.123</id>
<name>Resource 1</ABC>
</results>
<results>
<id>TEST.465</id>
<name>Resource 2</ABC>
</results>
</Items>
</File>
This is what I was trying -
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sap="http://www.sap.com/sapxsl"
xmlns:asx="http://www.sap.com/abapxml">
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<asx:abap version="1.0">
<asx:values>
<FILE>
<xsl:for-each select="/File">
<DUMMY1>
<HEAD>
<xsl:for-each select="/Items">
<DUMMY2>
<RESULTS>
<ID>
<xsl:value-of select="/results/id"/>
</ID>
<NAME>
<xsl:value-of select="/results/name"/>
</NAME>
</RESULTS>
</DUMMY2>
</xsl:for-each>
</HEAD>
</DUMMY1>
</xsl:for-each>
</FILE>
</asx:values>
</asx:abap>
</xsl:template>
</xsl:transform>
And my ABAP structure is :
TYPES: BEGIN OF ls_results,
resource TYPE string,
name TYPE string,
END OF ls_results.
TYPES: begin of ls_head,
results type table of ls_results with default key,
end of ls_head.
TYPES: Begin of ls_data,
head type table of ls_head with default key,
end of ls_data.
DATA: lt_data TYPE standard TABLE OF ls_data.
I have been stuck with this for a long time, so I'll be really grateful if you could kindly help me out on this.
Best Regards,
Sohini