Skip to Content

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.

BLOG_MessageMappingConcept.jpg

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.

BLOG_JavaMappingConcept.jpg

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.

http://scn.sap.com/community/pi-and-soa-middleware/blog/2013/03/13/write-java-mapping-directly-in-esr

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.

BLOG_Mapping.jpg

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.

BLOG_MappingTest.jpg

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.

BLOG_NWDS.jpg

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.

BLOG_OperationMapping.jpg

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.

BLOG_FlatFile.jpg

Hope it would help you to achieve complex file content conversion using java mapping in SAP PI.

Happy coding,

Ambuj Mishra

To report this post you need to login first.

5 Comments

You must be Logged on to comment or reply to a post.

  1. Syrine Trabelsi

    Hello Ambuj,

    Thanks for this tutorial. Just one question related to the configuration of the operation mapping. What is the type of the target message? because in my understanding is that ESR is handling XML files. How did you get a flat file?

    Best regards,
    Syrine

    (0) 
    1. ambuj mishra Post author

      Hi Syrine,
      You can select any dummy message type in your target interface. Because output stream of your java code in ESR (which are lines of flat files in above code) will replace that target xml before sending it to adapter.
      If you see the second screenshot where I have shown testing in ESR itself. At source you can see an incoming xml but after executing that mapping, it is converted into flat file format. Same flat file will be forwarded to your receiver adapter for writing. it doesn’t have to be an xml.

      Thanks,
      Ambuj

      (1) 
  2. Emir Morillo

    Hi ambuj,

    I do all the steps, but the file is not generated as the Message Mapping shows, should something be done in the Communication Channel?

    The output file is an XML.

    Any ideas?

    Regards,
    Emir Morillo

    (0) 
    1. ambuj mishra Post author

      Hi Emir, I know it’s very late response. I already mentioned at the end of blog.

      When you execute it end to end, you will get flat file in target folder as you are seeing in your message mapping, no special configuration required in channel.

      (0) 

Leave a Reply