Technology Blog Posts by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
naveen4796
Participant
8,939

Introduction:

In SAP Cloud Integration (CI and formerly known as CPI), Groovy scripts play a crucial role in customizing and fine-tuning integration flows. Whether you're manipulating XML structures, handling data transformations, or performing complex validations, Groovy scripts provide the flexibility you need. In this blog post, I’ll share several essential Groovy script solutions that address common challenges in SAP CI. These scripts, which you can integrate into your flows, include logic for sorting XML segments, managing data formats, and more.

1. Sorting XML Segments in an IDoc

When working with IDocs in SAP CI, the order of segments can be critical. This first script ensures that specific segments within an IDoc are sorted correctly according to a predefined order.

 

import com.sap.gateway.ip.core.customdev.util.Message
import groovy.xml.XmlUtil
import groovy.xml.StreamingMarkupBuilder

def Message processData(Message message) {
    def body = message.getBody(java.lang.String) as String
    def xml = new XmlSlurper().parseText(body)

    // Define the desired order of segments
    def desiredOrder = [
        'EDI_DC40',
        'ZAP2PO_MESSCONTRO',
        'ZAP2PO_OPTIONS',
        'ZAP2_POHEADER',
        'ZAP2_POITEM',
        'ZAP2_POACCOUNT',
        'ZAP2_POACCOUNTPROFITSEGMENT',
        'ZAP2_POSCHEDULE'
    ]

    // Ensure xml.IDOC is a Node and get its children
    def idocNode = xml.IDOC[0]
    def sortedChildren = idocNode.children().sort { a, b ->
        desiredOrder.indexOf(a.name()) <=> desiredOrder.indexOf(b.name())
    }

    // Rebuild the IDOC element with sorted children
    def builder = new StreamingMarkupBuilder()
    def sortedXml = builder.bind {
        ZAP2POCREATE {
            IDOC(BEGIN: '1') {
                sortedChildren.each { child ->
                    mkp.yield child
                }
            }
        }
    }.toString()

    // Set the sorted XML back to the message body
    message.setBody(sortedXml)

    return message
}

 

Explanation:

This script parses an incoming XML, sorts the segments within an IDoc according to a predefined order, and reconstructs the XML to ensure that downstream systems receive it in the expected format.

2. Replacing the Root Node of an XML Payload

Sometimes, you may need to replace the root node of an XML document to conform to a new schema or to meet specific integration requirements. The following Groovy script shows how to replace the root node of an XML payload in SAP CI.

 

import com.sap.gateway.ip.core.customdev.util.Message
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil

def Message processData(Message message) {
    def body = message.getBody(java.lang.String) as String
    def xml = new XmlSlurper().parseText(body)

    // New root node name
    def newRootNodeName = 'NewRootNode'

    // Build the new XML structure with the new root node
    def builder = new StreamingMarkupBuilder()
    def newXml = builder.bind {
        "${newRootNodeName}" {
            xml.children().each { child ->
                mkp.yield child
            }
        }
    }.toString()

    // Set the new XML back to the message body
    message.setBody(newXml)

    return message
}

 

#1 Test Execution result

naveen4796_0-1723487217379.png

2.a.groovyIDE_link

#contiva IDE tool

If you need to change the root element from <ZAP2POCREATE> to <NewRootNode>, this script makes it easy and efficient to handle such transformations within your SAP CI flows.

3. Remove XML Declaration

When working with XML documents in Groovy, you might need to remove the XML declaration, especially if you're processing the XML further or integrating it with other systems. The XML declaration can vary in format, including different cases for encoding, the use of single or double quotes, or even omitting the encoding attribute altogether.

XML declaration types:

Spoiler

<?xml version="1.0" encoding="UTF-8"?>
<?xml version='1.0' encoding='UTF-8'?>
<?xml version="1.0" encoding="utf-8"?>
<?xml version='1.0' encoding='utf-8'?>
<?xml version="1.0"?>
<?xml version='1.0'?>

Here’s a Groovy script that handles all these variations:

 

import com.sap.gateway.ip.core.customdev.util.Message;
import groovy.xml.XmlUtil;
import groovy.xml.MarkupBuilder;
import java.util.HashMap;
import java.util.Map;
import groovy.xml.StreamingMarkupBuilder;

def processData(Message message) {
    def body = message.getBody(java.lang.String) as String
    
        // Regular expression to match all variations of the XML declaration
        //Use (?i) within the regular expression to make it case-insensitive
    def xmlDeclarationPattern = /(?i)<\?xml.*version\s*=\s*['"]1\.0['"](.*encoding\s*=\s*['"](utf-8)['"])?\s*\?>/
    
    // Remove the XML declaration
    body = body.replaceAll(xmlDeclarationPattern, "")
    
    message.setBody(body) // Set the modified XML back to the message body
    return message
}

 

4. Mapping with Groovy - XML Input and XML Output

Using groovy to transform XML input into a custom XML output.

import com.sap.gateway.ip.core.customdev.util.Message
import groovy.xml.MarkupBuilder

def Message processData(Message message) {
    // Get the XML input as a string
    def body = message.getBody(String)
    def inputXml = new XmlSlurper().parseText(body)

    // Initialize StringWriter to hold the new XML content
    def writer = new StringWriter()
    def xmlBuilder = new MarkupBuilder(writer)

    // Handle single records ( 'Records' elements)
    xmlBuilder.root {
        User {
            firstName(inputXml.Records.name1.text())
            lastName(inputXml.Records.name2.text())
            email(inputXml.Records.mailaccount.text())
            phone(inputXml.Records.mailaccount.text())
            recordtype("User Account")
        }
    }
    
     //Handle unbounded records (multiple 'Records' elements)
   /** xmlBuilder.root {
        inputXml.Records.each{ recData ->
            User {
                firstName(recData.name1.text())
                lastName(recData.name2.text())
                email(recData.mailaccount.text())
                phone(recData.mailaccount.text())
                recordtype("User Account")
            }
        }
    } **/
    

    // Set the generated XML as the message body
    message.setBody(writer.toString())
    return message
}

#1 Test Execution - when the input contains one record

naveen4796_0-1723645268105.png

#2 Test Execution - when the input contains multiple records

naveen4796_1-1723645335370.png

 4.a.groovyIDE_link

5. Mapping with Groovy - JSON Input and JSON Output

Using groovy to transform XML input into a custom JSON output.

import com.sap.gateway.ip.core.customdev.util.Message
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder

def Message processData(Message message) {
    // Get the JSON input as a string
    def body = message.getBody(String)
    def inputJson = new JsonSlurper().parseText(body)

    // Initialize a map to build the new JSON content
    //Handle single record 
  /*  def jsonContent = [
        record: [
            firstName : inputJson.root.Records.name1,       //if input json is an error, even if it has one record, then define like this "inputJson.root.Records[0].name1"
            lastName : inputJson.root.Records.name2,
            email : inputJson.root.Records.mailaccount,
            phone : inputJson.root.Records.mailaccount,
            recordtype : "User Account"
        ]
    ]*/
    
    //Handle muliple records (multiple 'Records' elements)
    // Create a list to hold the JSON records
    def jsonRecords = []
    
    // Iterate over each <Records> element and build JSON objects
    inputJson.root.Records.each { record ->
        def jsonRecord = [
            firstName: record.name1,
            lastName: record.name2,
            email: record.mailaccount,
            phone: record.contactnumber,
            recordtype : "User Account"
        ]
        jsonRecords << jsonRecord
    }
    def jsonBuilder = new JsonBuilder(jsonRecords)

    // Set the generated JSON as the message body
    message.setBody(jsonBuilder.toPrettyString())
    return message
}

#1 Test Execution - when the input contains one record

naveen4796_2-1723648763062.png

#2 Test Execution - when the input contains multiple records

naveen4796_3-1723648773681.png

5.a.groovyIDE_link

Scripts 4 and 5 can be interchanged or customized as needed.

Conclusion:

In this blog post, we’ve covered several essential Groovy script solutions that address common challenges in SAP CI. 

Feel free to adapt these scripts to your specific integration needs, and don’t hesitate to reach out if you have any questions or suggestions for additional topics!

3 Comments