This weblog is about XML prcossing in ABAP. Part one, two and three of this weblog introduced some basic techniques for Simple Transformations. Now it’s time put all those things together to solve a simple task. Along the way I will discuss process control, modularization and mapping issues.
Process control with variables
Let’s assume we have a standardized family of XML specifications. Each specification uses the so called head-body pattern, furthermore that standardized header contains an ID that corresponds to a special interface version. Usually two different interfaces will have different body elements so you need a different transformation. We want to evaluate the ID and apply a certain transformation to the body element dependent on the ID mentioned before. Of course we could read that ID, return it to the calling ABAP program after skipping the rest of the XML document. Within ABAP we could do a case distinction and call different ST programs. But we can do better by defining a single ST program shown later.
At first let me show the XML example we want to process:
In the following we have another XML document that differs only in element: <id RT=”0815″/> . To keep things easy I want to solve following task: according to an ID given in the XML document I use a different transformation for the <body> element. If the ID is ‘4711’ I want to transform ‘1’ to ‘a’ and ‘2’ to ‘b’ in element <X1>. If the ID is ‘0815’ I’ll do just the other way: ‘1’ will be transformed to ‘a’ and ‘2’ to ‘b’.
So what do we need to solve this task? We have to use
- conditional transformations,
- mapping and
Just like in ABAP you have internal and external modularization. Internal modularization means that you can define different subtemplates within you ST program and call them using tt:apply.
External modularization means that you call another (external) ST program from within your program using the tt:call statement. Another possibilty is to include subtemplates from another ST program using tt:include. You can use this feature to define a set of basic templates as a library for your transformations. In the rest of this blog I won’t use this feature and restrict myself to the tt:call command.
If you already know the canonical representation of ABAP DDIC objects in asXML you can skip the following lines because the “canonical” mapping ST is just the same. That means that “2005-06-14” in XML corresponds to “20051406” in ABAP and “20:15:01” corresponds to “201501”. If you are unsure about a certain implicit mapping I suggest you to just try it using tt:copy that creates resp. reads asXML:
There are cases you need explicit conversions: currency units may be defined different in an ingoing XML document compared to your SAP system for example. You can define your own mapping by using the map-attribute in the ST program Z_TRANS_1:
Let’s define another ST program Z_TRANS_2 with a sligthly different mapping:
We will need both programs as subroutines later on.
Let’s come back to our original problem. We want to write one ST program that can evaluates a certain value in the <header> element. According that value we call Z_TRANS_1 resp. Z_TRANS_2 to convert the <body> element. We obtain following transformation Z_MAIN:
Let’s explain how this solution works. At first we assign the value of RT attribute of <id> element to a variable V and then give it back to the calling ABAP program to the root VERSION. Dependent on that value we call Z_TRANS_1 resp. Z_TRANS_2 with different roots using tt:cond-var which actually implements the case distinction we want to have: the check-attribute in <tt:cond-var check=”V=’4711′”> defines a condition that is independet from the XML-stream. We define two different conditions enclosed by <tt:switch-var>. The first case tt:cond-var, whose condition is met, is processed and the element tt:switch-var is left.
I used two roots ROOT1 and ROOT2 in above ST program for the sake of generality. It may seem to be a little bit redundant but in usually two different interfaces will have different bodies so you need different ABAP structures for serialization resp. deserialization.
You can test this transformation will following ABAP code:
In this issue examples for mapping, modularization and process control with variables have been shown. An application of conditional programming was a very easy “generic XML framework”. Instances of that “framework” have a standardized header but different bodies. Dependent on an ID in the header different sub template for conversion are called. In our example the used programe Z_TRANS_1 and Z_TRANS_2 use different mappings. Please be aware the mappings in ST programs are static and don’t allow ABAP callbacks to read certain values from the customizing for example. As a consequence in general you can’t expect to realize complex mappings that are common in data exchange without postprocessing.
Of course real XML frameworks are much more sophisticated and include rules for type libaries, design rules for entities, syntactic rules for encoding them, rules for composing schemas and so. To get maintainable and flexible code for processing XML documents defined by those XML frameworks of course much more work has to be done compared with the basic example above.
Conditional programming seems to be a difficult part of ST programming. I suggest that you read the ST documentation to answer these questions:
- Can you change the transformation
- such that it uses tt:cond instead of tt:cond-var?
- If you can, please give your solution as a reply to this weblog issue.
- If you think that it can’t be done that way, please give your reasons why.