Skip to Content
Technical Articles
Author's profile photo Fatih Pense

Groovy EDI Segment Counter (also known as $B2B_SEG_COUNTER)

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.



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 java.util.HashMap;

def Message processData(Message message) {

    String magicKeyword = '$B2B_SEG_COUNTER'

    def body = message.getBody(
    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
        // 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
                    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

    String result = sw.toString()

    return message;

def String getLocalName( groovy.util.Node node ){
    def 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 Vikas Kumar Singh shares the XSLT version of a similar solution. You should use it before the “Envelope Handling” step.


Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Robert Jancich
      Robert Jancich

      Hello Fatih Pense ,

      thank you for this hint. Actually I tried payload which also contained empty tags e.g. <PRI/> so with additional check the count fits nicely.

      if (possibleSegmentNode.value() != []) {
      segmentCount ++