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: 
raihan_siddiqui
Explorer
In SAP Cloud Integration (CPI), we all use Filter palette item in our various B2B scenarios to validate/filter the incoming payload. One of the most common XPath expression we use is to check whether a particular node in the incoming payload has a particular value.

In this blog, we will use W3C XPath and XQuery functions to validate incoming payload.

What is the benefit of this?


In our integrations, we often have our first step after fetching payload to remove unnecessary data for further processing. One option for this is using Message mapping, but that increases the size of the interface and hence the time complexity as well. CPI has provided us with a standard palette item to achieve our goals.

Pre-requisites for trying this integration scenario:



  1. CPI Access.

  2. Basic knowledge of palette items in CPI.


Setting up the interface:



IFlow overview


Suppose we are fetching a list of documents. We are getting the incoming payload as:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Document>
<DocID>10212</DocID>
<DocName>Passport</DocName>
</Document>
<Document>
<DocID>10214</DocID>
<DocName>Birth Certificate</DocName>
</Document>
<Document>
<DocID>10216</DocID>
<DocName>PAN</DocName>
</Document>
<Document>
<DocID>10212</DocID>
<DocName>Passport</DocName>
</Document>
<Document>
<DocID>1021</DocID>
<DocName>Driving License</DocName>
</Document>
</Root>

Now, our aim is to filter documents which have DocID as 10212 and 10214.

In many of the blogs found on SAP, you will see that they have set a property as DocIDList = ‘10212’,’10214’. This looks something like below:


Content modifier view


 

After this, they will use a filter palette item where the XPath expression would be:

/Root/Document[contains($DocIDList,DocID)]

However, the drawback of using "contains" and such property is that if we get a DocID in our incoming payload as a substring of the DocIDList, those documents will pass as well. If we run the iflow now, and keep the payload like mentioned above, the DocID 1021 will pass as well. You can see the output below:

 


Output after using contains


 

You can see it clearly in the output above that the DocID "1021" (which is a substring of 10212) also passed the filter. The reason for this is that when we use the function “contains”, it takes two arguments, and both are strings. Hence, our property is treated as a single string and NOT array of strings.

 The function “contains” can be seen from the official documentation of W3 XPath functions.

https://www.w3.org/TR/xpath-functions-31/#func-contains

The snapshot from the website is:

 


contains function signature


 

So, how do we tackle this scenario? The answer is simple. We have another function named as index-of. This function takes inputs of any type.

According to the official website, here is the signature of the function index-of:

 


index-of function signature


 

The link is: https://www.w3.org/TR/xpath-functions-31/#func-index-of

As you can see, we can set any type for the searching sequence as well as the element which needs to be searched. The return type of this function is integer which returns the index of the occurring element and it returns -1 in case the element does not exist.

This is the functionality which we are going to use in our case.

Now, we first need to store the array of strings in an ArrayList. We can do this via groovy script which is the second step of the iflow.

Here is the code snippet to set the elements of the list.
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.*;

def Message processData(Message message) {

def body = message.getBody();

List<String> list = new ArrayList<String>();
list.add("10212");
list.add("10216");

map = message.getProperties();
message.setProperty("DocIDList", list);

return message;

}



 

Note: To make this more dynamic, we can also set an externalized property and store the document IDs in a comma-separated manner. Then we can call that property in our script and dynamically create a list.

Once our ArrayList is set we will store it in a property and then we will put a filter palette item as our third step of iflow.

The XPath expression for it would be:

/Root/Document[index-of($DocIDList, DocID) ne -1]

This XPath expression will make sure that only those documents pass, who have DocID in the dynamically set DocIDList ArrayList.

Let us run the iflow now:

And Voila!

 


Output after using index-of


 

We only have the needed DocIDs.

Conclusion:


You might think that this can be achieved using (DocID/text() eq ‘10212’ or DocID/text() eq ‘10216’ ) as well, but the longer the list gets, the longer the XPath expression will become. The XPath function “contains” takes only strings as input arguments, and hence we cannot filter a string among an array of strings. To handle such scenario, we have to use the function “index-of” which takes any atomic type as arguments.

 

Hope this helps!

Thanks for reading!

Raihan Siddiqui

Associate Consultant, Capgemini.
2 Comments
DeepaliG
Explorer
Good read! Thanks for sharing.
naveenkumar111
Explorer
0 Kudos
Much anticipated logic, and it's working flawlessly.

Thanks for sharing.
Labels in this area