XI/PI: Convert Flat File to Deeply Nested XML Structures Using Only Graphical Mapping
Many a times, you are required to convert flat file structures to deeply nested structures like IDocs. StandardFile 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
!http://www.riyaz.net/blog/wp-content/uploads/2008/05/fcc-flat-xml-150×150.jpg|title=File Content Conversion (Click to enlarge)|height=150|style=border: 0pt none ; float: right; margin-left: 5px; margin-right: 5px|alt=File Content Conversion|width=150|class=alignright alignnone size-thumbnail wp-image-265|src=http://www.riyaz.net/blog/wp-content/uploads/2008/05/fcc-flat-xml-150×150.jpg!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 –
!http://www.riyaz.net/blog/wp-content/uploads/2008/05/child-node-mapping.jpg|title=Child node mapping using UDF nest|height=116|alt=Child node mapping using UDF nest|width=400|class=alignnone size-full wp-image-264|src=http://www.riyaz.net/blog/wp-content/uploads/2008/05/child-node-mapping.jpg!
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 = j1;<br /> for( i = 0; i < current.length; i+ ) {
for (;x<parent.length; j+,x+ ){
a = Integer.parseInt(parent );
b = Integer.parseInt(current );
c = Integer.parseInt(parent );
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 –
!http://www.riyaz.net/blog/wp-content/uploads/2008/05/im-test-result.jpg|title=Test Result|height=270|alt=Test Result|width=400|class=alignnone size-full wp-image-269|src=http://www.riyaz.net/blog/wp-content/uploads/2008/05/im-test-result.jpg!
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.
good written blog , however technically I don't see anything new in that. This is the traditional approach that everyone is taking and even it's much simpler if you use XSLT mapping.
Also the main reason for using conversion agent and SeeBurger is that EDI standard are very complex and in large no, and both this tools provides library for all the EDI stanradrd. That's why effort should not be put in parsing that complex structure.
I agree with you and appreciate your point of view.
Seeburger certainly has its advantages as you dont need to worry about structure complexity and also as the EDI standards evolve or get modified, Seeburger delivers new objects/patches that can be readily integrated.
At the same time note that some clients may not want to invest into Seeburger if all they need it for is a single scenario/process.
Regards,
Riyaz
Regards,
Riyaz
Node1 – Occurs 0..unbounded
Node2 – Occurs 0..unbounded
Can you suggest modification to your code? I appreciate your help in this regard.
Thanks
Krish
In my case Node1 is out of the hierarchy. Only Node2, Node3 and Node4 are nested under one another. And all the three are 0..unbounded. So I guess this solves your problem.
Let me know if I did not understand your concern correctly.
Thanks.
Regards,
Riyaz
I have a deep structure in my input flat file.
Something like this-
RecSet
|_Rec1
|_Rec2
|_BatchGroup(1:unbounded)
......... |_DetailGroup(1:unbounded)
..................|_Rec3
..................|_Rec4(1:unbounded)
..........|_BatchTotal
|_Rec5
|_Rec6
Is there an alternative to developing an adapter module specifically for this purpose since this cannot be handled in File content conversion of file adapter in PI?
Thanks.
Hi Riyaz,
Excellent blog.
I have similar requirement and trying with XSLT. I am facing issue when converting linear to deep structures in the inner loops.
Example:
Node3 – Occurs 0..unbounded and repeats under the preceding Node2.
When I have written For each loop for Node3.All Node3 nodes are getting repeated in each record instead of one for each record.
Could you please help me hoe to handle inner loops in XSLT