Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
pkaushiksrinivas
Explorer

Introduction


This blog covers some ideas and approaches on routing of messages based on a particular XPath condition in SAP CPI.

Requirement :



  • Flow : SAP S4 HANA --> CPI --> 3rd party SFTP

  • Source : IDOC, Target : External Definition

  • IDOCs having no /ZCUSTOM_ZINVOIC02_INV/IDOC/E1EDP01/ZCUSTOM_E1EDP01_SUBITEM/ZFLAG="A" need to be terminated in CPI and not sent to target system.

  • IDOCs having mixed values i.e combination of "A" and other values can be sent but mapping needs to be considered only for ZFLAG="A"

  • Source is IDOC and target is a custom XML External definition

  • Multiple IDOCs can be sent in a batch


3 approaches were explored as below :

Approach 1 :



  • Use a message mapping and apply logic for checking ZFLAG value at root IDOC level. Suppress IDOCs having no Lines in IDOC having ZFLAG=A.

  • Use a router in next step and check if count of IDOCs is zero.

    • If count is not zero, pass it to main mapping in default route where IDOC-External Definition mapping is done (Default Route)

    • If count is zero then end that batch here ( Router Condition : count(//IDOC) = 0 )




Approach 2 :



  • Use a Groovy Script which keeps a count of all items having ZFLAG="A" and sets the count as a Exchange Property

  • Use a router at next step to check if Exchange Property count is greater than zero

    • If count is not zero, pass it to default route where IDOC-External Definition mapping is done and sent ahead

    • If count is zero, then end that IDOC in CPI




Approach 3 :



  • Use a content modifier to capture all actual values of Flag in an Exchange Property and use another Exchange Property to capture the applicable value (Here it is "A")

  • Use a router in next step and check if Applicable Value Exchange Property value exists in Actual value exchange property.

    • If applicable value exists in actual value list, pass it to main mapping in default route where IDOC-External Definition mapping is done

    • If applicable value does not exist in actual value list, end that IDOC in CPI




All 3 approaches are covered in detail below :

Approach 1 : Filter Mapping + Router + Main Mapping Combination



Figure 1- Approach 1 : Filter Mapping + Router + Main Mapping


Step 1 : Message Mapping which suppresses the IDOCs which do not have even one line item with ZFLAG=A

  • Use a message mapping and apply filter of checking ZFLAG value at root IDOC level and at E1EDP01 segment (Rest segments can be mapped one-one)

  • Suppress IDOCs having no Line item in IDOC having ZFLAG=A in mapping.




Figure 2 - Mapping Logic for filtering IDOCs that do not have any line items with ZFLAG=A (Logic applicable for Root IDOC segment and E1EDP01 segment)


NOTE : After ifWithoutElse, a UDF is used which returns a single true, if atleast a single line item with ZFLAG=A exists in an IDOC, else, it will return false which will suppress that IDOC itself (UDF is not discussed here)

Step 2 : Conditional Routing

  • Step 2.1 : If count is not zero pass it to main mapping in default route where IDOC-External Definition mapping is done (Default Route)

  • Step 2.2 : If count is zero then end that batch here ( Router Condition : count(//IDOC) = 0 )



Figure 3 - Router Condition for terminating IDOCs


Step 3 : Split and Map IDOC to XML as applicable

 

Simulation Results for Positive test Case : When IDOCs in a batch contains atleast one line item with ZFLAG=A. 4 IDOCs triggered in a batch, 2 have no line items with ZFLAG=A and 2 IDOCs have mixed values



Figure 4 - Simulation result of Mapping Logic for positive test case i.e when batch of IDOCs have atleast one line having ZFLAG=A. Out of 4 IDOCs in a batch, 2 are having mixed values of ZFLAG and 2 are having no line items with ZFLAG=A which are suppressed as shown above.



Figure 5 - Simulation Result of iflow for positive test case i.e when batch of IDOCs have atleast one line having ZFLAG=A. Out of 4 IDOCs in a batch, 2 are having mixed values of ZFLAG and 2 are having no line items with ZFLAG=A which are suppressed in Mapping and the relevant filtered IDOCs are sent ahead.


 

Simulation Results for Negative test Case : When none of the IDOCs in a batch have line items with ZFLAG=A


Figure 6 - Simulation result of mapping logic for negative test case i.e when batch of IDOCs have no lines having ZFLAG=A. Out of 2 IDOCs in a batch, none of them are having line items with ZFLAG=A which are suppressed as shown above.



Figure 7 - Simulation Result of iflow for negative test case i.e when batch of IDOCs have no lines having ZFLAG=A. Out of 2 IDOCs in a batch, none of them are having line items with ZFLAG=A which are suppressed in Mapping out and hence count of IDOC is zero here, hence this batch is terminated in CPI.


 

Approach 2 : Groovy + Router + Main Mapping Combination



Figure 8 - Approach 2 : Groovy + Router + Main Mapping




  • Step 1 : Split the IDOCs

  • Step 2 : Groovy Script which keeps a count of all items having ZFLAG="A" and sets the count as a Exchange Property-ZFLAG_Count
    // Purpose of using this groovy - per requirement, if an IDOC has no Line item (E1EDP01) containing ZCUSTOM_E1EDP01_ITEM/ZFLAG=A, then no output XML for that IDOC should be created from CPI.
    // Below script will return the count of ZFLAG=A in Exchange property, If count > 1 then send idoc to mapping, else end such message in CPI

    import com.sap.gateway.ip.core.customdev.util.Message;
    import java.util.HashMap;
    import groovy.util.XmlSlurper ;
    import groovy.xml.XmlUtil;
    import org.w3c.dom.*;
    import javax.xml.parsers.*;
    import java.io.*;
    import java.io.StringReader;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import org.w3c.dom.Document;
    import org.xml.sax.InputSource;
    def Message processData(Message message)
    {
    def mapProperties = message.getProperties();

    //read message as string
    def body = message.getBody(java.lang.String) as String;

    //initialize variables
    def count=0;

    //Create a DocumentBuilder
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document doc = builder.parse(new InputSource(new StringReader(body)));
    doc.getDocumentElement().normalize();

    //Extract the root element
    Element root = doc.getDocumentElement();
    System.out.println("Root element " + doc.getDocumentElement().getNodeName());
    NodeList nList = doc.getElementsByTagName("E1EDP01");

    for (int temp = 0; temp < nList.getLength(); temp++)
    {
    Node nNode = nList.item(temp);
    Element eElement = (Element) nNode;

    if (eElement.getElementsByTagName("ZFLAG").item(0).textContent.equals("A"))
    count++;
    }
    message.setProperty("ZFLAG_Count", count);
    return message;

    }

     

  • Step 3 : Use a router at next step to check if Exchange Property ZFLAG_Count

    • Step 3.1 : if count is greater than zero, pass it to default route where IDOC-External Definition mapping is done and sent ahead (Default Route)

    • Step 3.2 : If No, then end that IDOC in CPI (Condition : ${property.ZFLAG_Count} = '0')
      Figure 9 - Router Configuration



  • Step 4 : Mapping IDOC-XML as applicable



Simulation Results for Positive test Case : When IDOC in a batch contains atleast one line item with ZFLAG=A. 4 IDOCs triggered in a batch, 2 have no line items with ZFLAG=A and 2 IDOCs have mixed values


Figure 10 - IDOCs having atleast one ZFLAG=A sent to default route.



Figure 11 - IDOCs having no ZFLAG=A ended in CPI


Simulation Results for Negative test Case : When none of the IDOCs in a batch have line items with ZFLAG=A


Figure 12 - No IDOCs in a batch contain line items with ZFLAG=A ended in CPI



Approach 3 : Content Modifier + Router + Main Mapping Combination



Figure 13 - Approach 3 : Content Modifier + Router + Main Mapping




  • Step 1 : Split the IDOCs

  • Step 2 : Use a content modifier

    • capture all actual values of ZFLAG in an Exchange Property (ZFLAG_ACTUAL_VALUES-string-join((//E1EDP01/ZCUSTOM_E1EDP01_SUBITEM/ZFLAG/text()),',')

    • capture all applicable values of ZFLAG in an Exchange Property (ZFLAG_APPLICABLE_VALUES). Here this value is hardcoded to "A" as per requirement. (This can also be externalized)




NOTE : Here another exchange property - ZFLAG_COUNT is used with XPath value : count(//E1EDP01[ZCUSTOM_E1EDP01_SUBITEM/ZFLAG="A"])(We can leverage this as an alternative to Groovy script in Approach 2 as well!)



Figure 14 - Content Modifier Exchange Properties (ZFLAG_COUNT value can be levraged instead of Approach 2 Groovy script as well!)

 


  • Step 3 : Use a router in next step and check if Exchange Property-ZFLAG_APPLICABLE_VALUES value exists in exchange property-ZFLAG_ACTUAL_VALUES.

    • Step 3.1 : If Yes, pass it to main mapping in default route where IDOC-External Definition mapping is done (Default Route)

    • Step 3.2 : If No, end that IDOC in CPI (Condition : ${property.ZFLAG_ACTUAL_VALUES} not contains ${property.ZFLAG_APPLICABLE_VALUES}


      Figure 15 - Router Configuration





  • Step 4 : Mapping as applicable



Simulation Results for Positive test Case : When IDOC in a batch contains atleast one line item with ZFLAG=A. 4 IDOCs triggered in a batch, 2 have no line items with ZFLAG=A and 2 IDOCs have mixed values


Figure 16 - IDOCs having atleast one ZFLAG=A sent to default route



Figure - IDOCs having no ZFLAG=A ended in CPI


Simulation Results for Negative test Case : When none of the IDOCs in a batch have line items with ZFLAG=A


Figure 17 - No IDOCs in a batch contain line items with ZFLAG=A ended in CPI


 

Summary


Multi-dimensional approaches/ideas were shared for a requirement to bifurcate data based on repetitive XPath as explained above.

Hope this blog was informative with respect to the ideas on approaching a requirement with different ways and will be relevant to the CPI/PI/PO Developers/Consultants.

Constructive comments or feedback/suggestions if any on the above are welcome.

References


Filtering the IDoc Segment in SAP CPI | SAP Community


[SAP Cloud Platform-Integration] Content Filter in Detail | SAP Blogs


XPath Count | Mendix Documentation


Using XPath Functions (oracle.com)


Content Modifier Xpath Data Type | SAP Community


Get to know Camel’s Simple expression language in SAP Cloud Integration | SAP Blogs


Please explain Conditional router in detail in CPI | SAP Community


Concat same node field in XPath of CPI | SAP Community


Define Router | SAP Help Portal

2 Comments
Labels in this area