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.

 

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 Vikas Kumar Singh shares the XSLT version of a similar solution. You should use it before the “Envelope Handling” step.

 

Assigned Tags

      3 Comments
      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 ++
      }

       

      BR,

      Robert

      Author's profile photo Fatih Pense
      Fatih Pense
      Blog Post Author

      Thank you for the improvement Robert!

      Regards,
      Fatih

      Author's profile photo Young Soo Kim
      Young Soo Kim

      Hi Faith Pense

       

      Would you able to provide for CNT segment on D_6066 field for calculating line items on DESADV edifact ? I was posted and questioned for that matter on SCN.

      -How to populate segment CNT from EDIFACT in SAP CPI MAG or XSLT | SAP Community

      Is it possible to get line-item count function on MAG or XSLT or Groovy needs same as above additional development?

      All the Best