Technology Blog Posts by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
fatihpense
Active Contributor
4,982
EDIFACT messages require a total segment count in the segment UNT. X12 messages require the same information in segment SE data element 96.

In SAP Process Integration/Orchestration(PI/PO) this requirement was handled by mapping the constant $B2B_SEG_COUNTER to the relevant field. SAP Cloud Integration doesn't have this feature yet, but we can create a Groovy script that replicates exactly the same behavior.


You can put this script just before the "XML to EDI converter" step, or after "EDIFACT Post-processing" step. It is flexible and it can be used when the message body has the XML root element starting with M_, or the root element is Interchange.


You can map $B2B_SEG_COUNTER to any field. You can use the constant function in Integration Advisor.



 

Script


Note that groovy.util.Node returns String in Groovy IDE and a QName object in Cloud Integration. This behavior is flexible in the Groovy spec. "getLocalName" function handles this difference.
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;


def Message processData(Message message) {

String magicKeyword = '$B2B_SEG_COUNTER'

def body = message.getBody(java.io.Reader)
def parser = new XmlParser()
def ediXmlDoc = parser.parse(body)

Integer segmentCount = 0



//find message and count segments inside
ediXmlDoc.breadthFirst().findAll { possibleMessageNode ->
// GroovyIDE returns String, Cloud Integration returns QName here.
// println possibleMessageNode.name().getClass()
// The implementation is flexible in the Class spec. .name() function returns java.lang.Object.
// It is possible that since this input has no namespace, it returns string.


// it is a message node
if ( getLocalName(possibleMessageNode).startsWith("M_") ){
possibleMessageNode.breadthFirst().findAll { possibleSegmentNode ->
// it is a segment node
if ( getLocalName(possibleSegmentNode).startsWith("S_") ){
// println possibleSegmentNode.name()
segmentCount ++
}
}
}
}

// find nodes to be filled
ediXmlDoc.breadthFirst().findAll { node ->
if (node.localText().size() > 0 && node.localText().first() == magicKeyword ){
node.value = segmentCount
}
}





// Write document to body
def sw = new StringWriter()
def xmlNodePrinter = new XmlNodePrinter(new PrintWriter(sw))
xmlNodePrinter.with {
preserveWhitespace = true
}
xmlNodePrinter.print(ediXmlDoc)

String result = sw.toString()
message.setBody(result)

return message;
}


def String getLocalName( groovy.util.Node node ){
def name = node.name() // can be java.lang.String or groovy.xml.QName or another object!
String localName = ""
if (name instanceof groovy.xml.QName) {
groovy.xml.QName qname = (groovy.xml.QName) name
localName = qname.getLocalPart()
}
else {
localName = name.toString()
}
return localName
}

 

GitHub Repository for Contributions


You can see this example & others at the GitHub repository. You can star the project or even watch👀 for all future updates!

Contributions are welcome! I can help with the description or the code if you want.

 

Related Blog Posts


This blog post by vicky20691 shares the XSLT version of a similar solution. You should use it before the "Envelope Handling" step.

 
4 Comments