Concept:
Here I will explore an alternative way of file content conversion without using Module configuration (XML2PLAIN) or standard file content conversion, present at receiver file adapter.
Above diagram depicts how normally we do content conversion in a standard way.
Recently, I had gone through a requirement where I needed to convert a complex nested xml like below, into a flat file.
<Record>
<Header>
</Header>
<Detail>
<Detail1>
</Detail1>
<Detail2>
<SubDetail1>
</SubDetail1>
</Detail2>
<Detail3>
<SubDetail2>
<DeepSubDetail3>
</DeepSubDetail3>
</SubDetail2>
</Detail3>
</Detail>
<Trailer>
</Trailer>
</Record>
Additionally, as per the requirement while generating flat file, each field should have padded with different amount of spaces and lots of fields and lines were optional and conditional, so I wanted to have full control on each field of each line in flat file.
I didn’t want to customize adapter module, so I come up with following solution.
Here I am taking my input xml as input stream in java mapping. I am creating each line of my flat file as per requirement by padding spaces and all. And resulted output stream is written by file adapter directly into flat file.
No module configuration or file content conversion is required at adapter level processing.
Real Time Scenario and Code snippets:
Let’s take a real sample input xml from which we will be going to generate a flat file using above concept.
Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:MT_Input xmlns:ns0="urn:example">
<Record>
<Header>
<RecordType>HDR</RecordType>
<FileName>INPUT.TXT</FileName>
<Data1>110011.24022014</Data1>
<Data2>AM</Data2>
</Header>
<Invoice>
<RecordType>INV</RecordType>
<Data>1010021-PAY</Data>
<Source>AMERP </Source>
<Filler>0000000000</Filler>
<MSG_TO_VND>
<RecordType>MSG_TO_VND</RecordType>
<Data>2100-ORDER</Data>
<DescriptionType>NEW ORDER BY AM</DescriptionType>
</MSG_TO_VND>
<MSG_INV_DESC>
<RecordType>MSG_TO_DESC</RecordType>
<Data>PAY INV-1010021</Data>
<DescriptionType>PAY INV BY AM</DescriptionType>
</MSG_INV_DESC>
<DIT>
<RecordType>DIT</RecordType>
<Data>1100.ORDER.NEW</Data>
<DescriptionType >NEW ORDER 1100 24022014</DescriptionType>
<MSG_TRN_DESC>
<RecordType>MSG_TRN_DESC</RecordType>
<Data>PAY ORDER 11001010021</Data>
<DescriptionType>NEW PAY ORDER BY AM</DescriptionType>
</MSG_TRN_DESC>
</DIT>
</Invoice>
<Trailer>
<RecordType>TRLR</RecordType>
<TotalCount>10.00000</TotalCount>
<Filler>1111111111</Filler>
</Trailer>
</Record>
</ns0:MT_Input>
Our expected output flat file will be,
Output Flat file:
HDR INPUT.TXT 110011.24022014 AM
INV 1010021-PAY AMERP 0000000000
MSG_TO_VND 2100-ORDER NEW ORDER BY AM
MSG_TO_DESC PAY INV-1010021 PAY INV BY AM
DIT 1100.ORDER.NEW NEW ORDER 1100 24022014
MSG_TRN_DESC PAY ORDER 11001010021 NEW PAY ORDER BY AM
TRLR 10.00000 1111111111
SAP PI 7.3 and above: (Using Message Mapping)
For PI 7.3 and above, you can write java mapping directly in ESR in message mapping as explained in Sunil's blog post.
I would recommend this approach as we can test our java mapping in test tab of message mapping right there.
I have written a java code to parse this sample input xml and convert it into flat file as expected. You can edit this code as per your requirement in Netweaver development studio or any Jdk by importing appropriate mapping libraries.
Sample code:
public void transform(TransformationInput in, TransformationOutput out) throws StreamTransformationException {
try{
// Instantiating output stream to write at Target message
OutputStream os = out.getOutputPayload().getOutputStream();
// building a new document to parse input stream i.e. our source message
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(in.getInputPayload().getInputStream());
//Instantiating HeaderParser class
HeaderParser hparser= new HeaderParser();
// retrieving header line of flat file
String strHeader=hparser.parseHeaderString(doc);
// Writing header line at output stream
os.write(strHeader.getBytes());
//Instantiating InvoiceParser class
InvoiceParser iparser= new InvoiceParser();
// retrieving Invoice lines of flat file
String[] strInvoice=iparser.parseInvoiceString(doc);
for (int i=0;i<strInvoice.length;i++)
{
// Writing each invoice line at output stream
os.write(strInvoice[i].getBytes());
}
//Instantiating TrailerParser class
TrailerParser tparser= new TrailerParser();
// retrieving Trailer line of flat file
String strTrailer=tparser.parseTrailerString(doc);
// Writing Trailer line at output stream
os.write(strTrailer.getBytes());
os.flush();
os.close();
}
catch (Exception e)
{
throw new StreamTransformationException(e.getMessage());
}
}
// Header parser class
public class HeaderParser {
public String parseHeaderString(Document doc){
String strInput="";
NodeList nList = doc.getElementsByTagName("Header");
Node nNode = nList.item(0);
Element element= (Element) nNode;
//Forming header line
strInput=(element.getElementsByTagName("RecordType").item(0).getTextContent()+ " “
+element.getElementsByTagName("FileName").item(0).getTextContent()+ " "
+element.getElementsByTagName("Data1").item(0).getTextContent()+ " "
+element.getElementsByTagName("Data2").item(0).getTextContent()+ " " )
+"\n";
return strInput;
}
}
//Invoice Parser class
public class InvoiceParser {
public String[] parseInvoiceString(Document doc) {
NodeList nlistInv = doc.getElementsByTagName("Invoice");
String[] strInput = new String[nlistInv.getLength()];
int j = 0;
try {
//looping Invoice tag
for (int i = 0; i < nlistInv.getLength(); i++) {
Node nNode = nlistInv.item(i);
NodeList n1 = nNode.getChildNodes();
Element e1 = (Element) n1;
//Nodes under Invoice tag
NodeList n2 = e1.getElementsByTagName("MSG_TO_VND");
NodeList n4 = e1.getElementsByTagName("MSG_INV_DESC");
NodeList n6 = e1.getElementsByTagName("DIT");
// Converting Invoice node into element
Element element = (Element) nNode;
//Fetching all text nodes value under Invoice tag
String recordType=element.getElementsByTagName("RecordType").item(0).getTextContent()+" ";
String data=element.getElementsByTagName("Data").item(0).getTextContent();
String source=element.getElementsByTagName("Source").item(0).getTextContent();
String filler=element.getElementsByTagName("Filler").item(0).getTextContent();
//forming 1st line of strInput[i], Maintain the order of values
strInput[i]= recordType
+ data
+ source
+ filler
+"\n";
//Assuming MSG_TO_VND tag is optional within invoice tag. Checking MSG_TO_VND tag existence
if (n2.getLength()>0)
{
Node n3 = n2.item(j);
// Converting MSG_TO_VND node into element
Element e2 = (Element) n3;
// Forming next Line of strInput[i], if exist
strInput[i]=strInput[i]+
e2.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+ e2.getElementsByTagName("Data").item(0).getTextContent()+" "
+ e2.getElementsByTagName("DescriptionType").item(0).getTextContent()+" "
+ "\n";
}
// MSG_INV_DESC tag within Invoice tag. Assuming it is mandatory tag.
Node n5 = n4.item(j);
// Converting MSG_INV_DESC node into element
Element e4 = (Element) n5;
// Forming next Line of strInput[i], if exist
strInput[i]=strInput[i]+
e4.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+ e4.getElementsByTagName("Data").item(0).getTextContent()+ " "
+ e4.getElementsByTagName("DescriptionType").item(0).getTextContent()+ " "
+"\n";
//looping DIT tag within Invoice.
for (int m = 0; m < n6.getLength(); m++) {
Node n7 = n6.item(m);
// Converting DIT node into element
Element e5 = (Element) n7;
NodeList ditn = e5.getElementsByTagName("MSG_TRN_DESC");
//Fetching all text nodes value under DIT tag
String RecordType=e5.getElementsByTagName("RecordType").item(0).getTextContent();
String ditdata=e5.getElementsByTagName("Data").item(0).getTextContent();
String descriptiontype=e5.getElementsByTagName("DescriptionType").item(0).getTextContent();
// Forming next line of strInput[i], if exist, maintain order of values
strInput[i]=strInput[i]+
RecordType+" "
+ ditdata+" "
+ descriptiontype+" "
+"\n";
//Assuming MSG_TRN_DESC tag is optional within DIT tag. Checking MSG_TRN_DESC tag existence
if (ditn.getLength()>0)
{
Node ditno = ditn.item(j);
// Converting MSG_TRN_DESC node into element
Element dite = (Element) ditno;
// Forming next Line of strInput[i], if exist
strInput[i]=strInput[i]+
dite.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+ dite.getElementsByTagName("Data").item(0).getTextContent()+" "
+ dite.getElementsByTagName("DescriptionType").item(0).getTextContent()+" "
+ dite.getElementsByTagName("Filler").item(0).getTextContent()+" "
+ "\n";
}
}
}
}
catch (Exception e) {
System.out.println(e);
}
return strInput;
}
}
//Trailer parser class
public class TrailerParser {
public String parseTrailerString(Document doc){
String strInput="";
NodeList nList = doc.getElementsByTagName("Trailer");
Node nNode = nList.item(0);
Element element = (Element) nNode;
// Forming Trailer line
strInput=(element.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+element.getElementsByTagName("TotalCount").item(0).getTextContent()+ " "
+element.getElementsByTagName("Filler").item(0).getTextContent()+ " ");
return strInput;
}
}
You can directly copy above java code and paste it into Function tab in message mapping under "Attributes and Methods" area as explained in Sunil's blog. Don't forget to import appropriate libraries.
Now, your message mapping will behave like java mapping. While executing this message mapping, first your java code under function tab gets executed, after that graphical mapping if there is any present.
You can test this java mapping by giving sample input xml in test tab at source. You will get Output flat file as expected at target.
All SAP PI Versions: (Using Imported Archive)
If you are working on PI version < 7.3. You can do this using imported archive by importing your java mapping code in ESR and then use it into Operation mapping.
Open any Java SDK (NWDS, Eclipse, Netbeans etc.).
Create a java project.
Create FileParser.java, HeaderParser.java, InvoiceParser.java and TrailerParser.java class without having Main method.
Paste following code in respective java classes.
FileParser:
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
public class FileParser extends AbstractTransformation{
public void transform(TransformationInput in, TransformationOutput out) throws StreamTransformationException {
try{
OutputStream os = out.getOutputPayload().getOutputStream();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(in.getInputPayload().getInputStream());
//Header
HeaderParser hparser= new HeaderParser();
String strHeader=hparser.parseHeaderString(doc);
os.write(strHeader.getBytes());
//Invoice
InvoiceParser iparser= new InvoiceParser();
String[] strInvoice=iparser.parseInvoiceString(doc);
for (int i=0;i<strInvoice.length;i++)
{
os.write(strInvoice[i].getBytes());
}
//Trailer
TrailerParser tparser= new TrailerParser();
String strTrailer=tparser.parseTrailerString(doc);
os.write(strTrailer.getBytes());
os.flush();
os.close();
}
catch (Exception e)
{
throw new StreamTransformationException(e.getMessage());
}
}
}
HeaderParser:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class HeaderParser {
public String parseHeaderString(Document doc){
String strInput="";
NodeList nList = doc.getElementsByTagName("Header");
Node nNode = nList.item(0);
Element element= (Element) nNode;
strInput=(element.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+element.getElementsByTagName("FileName").item(0).getTextContent()+ " "
+element.getElementsByTagName("Data1").item(0).getTextContent()+ " "
+element.getElementsByTagName("Data2").item(0).getTextContent()+ " " )
+"\n";
return strInput;
}
}
InvoiceParser:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class InvoiceParser {
public String[] parseInvoiceString(Document doc) {
NodeList nlistInv = doc.getElementsByTagName("Invoice");
String[] strInput = new String[nlistInv.getLength()];
int j = 0;
try {
//looping Invoice tag
for (int i = 0; i < nlistInv.getLength(); i++) {
Node nNode = nlistInv.item(i);
NodeList n1 = nNode.getChildNodes();
Element e1 = (Element) n1;
//Nodes under Invoice tag
NodeList n2 = e1.getElementsByTagName("MSG_TO_VND");
NodeList n4 = e1.getElementsByTagName("MSG_INV_DESC");
NodeList n6 = e1.getElementsByTagName("DIT");
// Converting Invoice node into element
Element element = (Element) nNode;
//Fetching all text nodes value under Invoice tag
String recordType=element.getElementsByTagName("RecordType").item(0).getTextContent()+" ";
String data=element.getElementsByTagName("Data").item(0).getTextContent();
String source=element.getElementsByTagName("Source").item(0).getTextContent();
String filler=element.getElementsByTagName("Filler").item(0).getTextContent();
//forming 1st line of strInput[i], Maintain the order of values
strInput[i]= recordType
+ data
+ source
+ filler
+"\n";
//Assuming MSG_TO_VND tag is optional within invoice tag. Checking MSG_TO_VND tag existence
if (n2.getLength()>0)
{
Node n3 = n2.item(j);
// Converting MSG_TO_VND node into element
Element e2 = (Element) n3;
// Forming next Line of strInput[i], if exist
strInput[i]=strInput[i]+
e2.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+ e2.getElementsByTagName("Data").item(0).getTextContent()+" "
+e2.getElementsByTagName("DescriptionType").item(0).getTextContent()+" "
+ "\n";
}
// MSG_INV_DESC tag within Invoice tag. Assuming it is mandatory tag.
Node n5 = n4.item(j);
// Converting MSG_INV_DESC node into element
Element e4 = (Element) n5;
// Forming next Line of strInput[i], if exist
strInput[i]=strInput[i]+
e4.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+ e4.getElementsByTagName("Data").item(0).getTextContent()+ " "
+ e4.getElementsByTagName("DescriptionType").item(0).getTextContent()+ " "
+"\n";
//looping DIT tag within Invoice.
for (int m = 0; m < n6.getLength(); m++) {
Node n7 = n6.item(m);
// Converting DIT node into element
Element e5 = (Element) n7;
NodeList ditn = e5.getElementsByTagName("MSG_TRN_DESC");
//Fetching all text nodes value under DIT tag
String RecordType=e5.getElementsByTagName("RecordType").item(0).getTextContent();
String ditdata=e5.getElementsByTagName("Data").item(0).getTextContent();
String descriptiontype=e5.getElementsByTagName("DescriptionType").item(0).getTextContent();
// Forming next line of strInput[i], if exist, maintain order of values
strInput[i]=strInput[i]
+ RecordType+" "
+ ditdata+" "
+ descriptiontype+" "
+"\n";
//Assuming MSG_TRN_DESC tag is optional within DIT tag. Checking MSG_TRN_DESC tag existence
if (ditn.getLength()>0)
{
Node ditno = ditn.item(j);
// Converting MSG_TRN_DESC node into element
Element dite = (Element) ditno;
// Forming next Line of strInput[i], if exist
strInput[i]=strInput[i]+
dite.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+ dite.getElementsByTagName("Data").item(0).getTextContent()+" "
+ dite.getElementsByTagName("DescriptionType").item(0).getTextContent()+" "
+ dite.getElementsByTagName("Filler").item(0).getTextContent()+" "
+ "\n";
}
}
}
} catch (Exception e) {
System.out.println(e);
}
return strInput;
}
}
TrailerParser:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class TrailerParser {
public String parseTrailerString(Document doc){
String strInput="";
NodeList nList = doc.getElementsByTagName("Trailer");
Node nNode = nList.item(0);
Element element = (Element) nNode;
strInput=(element.getElementsByTagName("RecordType").item(0).getTextContent()+ " "
+element.getElementsByTagName("TotalCount").item(0).getTextContent()+ " "
+element.getElementsByTagName("Filler").item(0).getTextContent()+ " ");
return strInput;
}
}
You can edit above code as per your requirement. Also you can add additional classes, if required.
Export all java files in your java project as JAR.
Make an imported archive in ESR.
Browse generated jar file in imported archive.
Select "FileParser" class (the class in which you have implemented transform method) in operation mapping while choosing java mapping.
You can test it only end to end.
Your output stream from java mapping will be written directly at receiver adapter.
Your generated flat file would be like below.
Hope it would help you to achieve complex file content conversion using java mapping in SAP PI.
Happy coding,
Ambuj Mishra
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
5 | |
5 | |
4 | |
3 | |
3 | |
3 | |
3 | |
3 | |
3 | |
2 |