Many a times, you are required to convert flat file structures to deeply nested structures like IDocs. Standard File Content Conversion allows you to convert the incoming file to flat XML structures only i.e. only one level of nesting is possible. Converting incoming file to deeply nested structures would require use of either custom developed adapter modules or third-party conversion agents.
This article provides a workaround to accomplish the same thing by using only the graphical mapping. William had a similar requirement, and we came up with a generic solution which is described below.
Lets say we have an incoming flat file with structure as described below –
Node1 – Occurs 0..1
Node2 – Occurs 0..unbounded
Node3 – Occurs 0..unbounded
Node4 – Occurs 0..unbounded
And the target structure is as shown below –
Node1 – Occurs 0..1
Node2 – Occurs 0..unbounded
Node3 – Occurs 0..unbounded and repeats under the preceding Node2
Node4 – Occurs 0..unbounded and repeats under the preceding Node3
Due to limitation of the standard File adapter, it is not possible to directly convert the incoming file to the deeply nested target structure. Hence we will use a two step message mapping to attain the required result.
First, we will use file content conversion as shown to covert the incoming file to flat XML structure as supported by the adapter. Click the image on the right to see an enlarged view. We will then use two-step message mapping to convert the flat XML to a nested XML. Figure below shows the flat XML structure generated by the file adapter using file content conversion.
Our aim is to convert the above flat structure to a nested shown below –
Note that there is no common element between parent and child nodes (e.g. Node2 and Node3, or Node3 and Node4) which we could use to determine corresponding parent node for each child node.
Hence, we need to create an intermediate message type which will establish a relationship between the parent and child nodes. We have achieved this by adding id attributes to each of the nodes as shown below.
The id attribute is mapped using a user defined function globalCounter which records the order in which the nodes appear in the source structure. The variable used to store the count is a global variable and is incremented every time a node is found in the source structure (irrespective of the node name).
Create one-to-one message mapping between source message and the intermediate message. Map the id attribute in the target with the globalCounter function.
The Java code of the globalCounter function is given below –
public String globalCounter(Container container){
GlobalContainer globalContainer;
globalContainer = container.getGlobalContainer();
Object o = globalContainer.getParameter("count");
Integer i;
if ( o == null ) i = new Integer( 0 );
else i = (Integer)o;
i = new Integer(i.intValue() + 1 );
globalContainer.setParameter("count", i );
return i.toString();
}
Now create another message mapping to map the intermediate message type to the target message type. The message mapping is shown below.
Node 1 is directly mapped to Node1 in the target as this node is not part of any hierarchy. The topmost parent node Node2 is mapped using removeContexts function.
All the nodes appearing below the topmost node (Node3 and Node4 in this case) have been mapped using removeContexts function and user defined nest function as shown below –
The first parameter to the nest function is the id attribute of the parent node while the second parameter is the id attribute of the current node (child node). Both parameters have been first processed with removeContexts function before passing them to the nest function. The third parameter is the actual value of the node that needs to passed on to the target structure. Below is the Java code for the nest function.
public void nest(String[] parent,String[] current,String[] node,ResultList result,Container container){
int i, j;
int a, b, c;
int x;
j = 0;
x = j+1;
for( i = 0; i < current.length; i++ ) {
for (;x<parent.length; j++,x++ ){
a = Integer.parseInt(parent [j]);
b = Integer.parseInt(current [i]);
c = Integer.parseInt(parent [x]);
if ( a < b ) {
if(c > b ) {
result.addValue(node[i]);
break;
}
else if (c < b) {
result.addContextChange();
}
}
}
if (x == parent.length) {
result.addValue(node[i]);
}
}
}
PS: If you are new to the idea of context handling, do read An Introduction to Context Handling.
Once this is done, create an interface mapping between the source and target interface and provide the mapping programs in the correct order i.e. first the mapping between source and intermediate message and then the one between intermediate and target structure. The same is shown below –
Now you can test the interface mapping locally and then test your scenario by doing appropriate directory configuration. Interface mapping test result is shown in the figure below –
Thus, we have seen how we can use plain file adapter and graphical mapping to convert a flat file to a deeply nested XML structure.
This idea could even be extended to convert EDI documents to IDoc structures as an alternative to third-party EDI adapters like Seeburger.