Skip to Content
Author's profile photo Eng Swee Yeoh

HCI: Parse XML easily with Groovy scripts

Introduction

HCI allows the usage of scripting languages in Integration Flows which can be used to enhance the functionality of the integration flow. Groovy scripts or Javascript can be implemented as a Message Transformer block or as a User Defined Function for Message Mappings.

Groovy is a dynamic language with native functionality to handle XML processing easily. Compared to Java, implementing logic for XML processing is really simple in Groovy, it is not as complex as DOM and have a low memory footprint as it is based on SAX.

In this blog, I will share some simple examples of how XML can be parsed easily in Groovy.

Examples

The examples below will all use the following input XML payload.

Input Payload

<?xml version='1.0' encoding='UTF-8'?>
<Records>
  <Line>
  <Field1>ABC</Field1>
  <Field2>123</Field2>
  <Field3>XXX</Field3>
  <Field4>567890</Field4>
  </Line>
</Records>




Scenario 1 – Read-only access to input XML

For read-only access to the input XML, it is recommended to use groovy.util.XmlSlurper. XmlSlurper contains a parseText() method which returns a GPathResult for the root element. Using this GPathResult object, accessing the content of the document can easily be done in an XPath-like manner. As shown in the logic below, the text contents of /Records/Line/Field1 and /Records/Line/Field4 are accessed using dot notation without any further declarations or DOM-like complex logic.

Logic

  public void parse(String input) {
    def root = new XmlSlurper().parseText(input);
    def field1 = root.Line.Field1.text();
    def field4 = root.Line.Field4.text();
    System.out.println("Value of /Records/Line/Field1 = " + field1);
    System.out.println("Value of /Records/Line/Field4 = " + field4);
  }



Below is the console output for the above example verifying the successful extraction of the two field contents.

/wp-content/uploads/2016/01/output1_874599.png

Scenario 2 – Change content of a field in input XML

If the input XML needs to be updated/changed during parsing, it is recommended to use groovy.util.XmlParser instead. Similar to above, it contains a parseText() method but returns a Node for the root element. Similarly, using GPath dot notation, content of the field can be directly modified as shown below for /Records/Line/Field1.

Logic

  public static void change(String input) {
    def root = new XmlParser().parseText(input);
    root.Line.Field1[0].value = "MyChangedField";
    System.out.println(XmlUtil.serialize(root));
  }


Below is the console output verifying the successful modification of the field.

/wp-content/uploads/2016/01/output2_874600.png

Scenario 3 – Add a new field in input XML

Similar to scenario 2, XmlParser is used to parse the input XML. In order to add a new field, the appendNode() method is used to add a new field and initialize the text content in it.

Logic

  public static void add(String input) {
    def root = new XmlParser().parseText(input);
    root.Line[0].appendNode("Field5", [:], "MyNewField");
 
    System.out.println(XmlUtil.serialize(root));
  }

Below is the console output verifying the successful addition of a new field in the XML payload.

/wp-content/uploads/2016/01/output3_874623.png

Conclusion

As demonstrated from the examples above, parsing of XML content is significantly simpler to implement in Groovy with the use of XmlParser and XmlSlurper.

Reference

The Groovy programming language – Processing XML

Assigned Tags

      20 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Bhavesh Kantilal
      Bhavesh Kantilal

      Hello,

      Are you aware of any modes to debug the Groovy Script in HCI during the runtime?

      I have added System.out.println statements but not sure which console this gets printed to!

      Regards,

      Bhavesh

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      Hi Bhavesh

      Unfortunately I don't. I haven't come across any documentation on that (in whatever little we have of HCI!).

      A long windy way that I used was to store values in property and route the message to the following HTTP logging server. Property values in HCI will be shown as HTTP property on the server's logs.

      Testing: Test Tools...Part 1 *HTTP *

      Regards

      Eng Swee

      Author's profile photo Bhavesh Kantilal
      Bhavesh Kantilal

      Hello Eng Swee,

      Thanks for your feedback and hint on using the HTTP Test Tool.

      Meanwhile, I was able to figure this out. The HCI Developer's Guide has this info.

      The MessageLog is accessible using the below piece of code. Was thereby able to add some Trace Entries and see what's happening within my Groovy Script.

      def messageLog = messageLogFactory.getMessageLog(message) messageLog.setStringProperty("Greeting", "Hello World!")

      Regards,

      Bhavesh

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      Nice one, Bhavesh.

      I had a look at the online documentation and it looks like it has been updated since I used it during my trial access. 🙂

      Author's profile photo Bhavesh Kantilal
      Bhavesh Kantilal

      The Fun and the Bane of Cloud, Change faster than one can comprehend 😏

      I am glad I could figure this out and thanks for all the HCI Blogs.. I hope to share my part of the learnings sometime soon!

      Author's profile photo Gabor Szigeti
      Gabor Szigeti

      Hi Bavesh,

      System.out.println entries are visible in the tail log of the IFLMAP node (not in the MPL)

      Regards,

      Gabor

      Author's profile photo Lavanya Musuvadhi Mothilal
      Lavanya Musuvadhi Mothilal

      Hi Eng Swee,

      Our use case is to convert the output XML message (from a receiver) from one format to another via scripts in HCI.

      Do you have any recommendations to do the same ?

      Can we use XSLT here?

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      Hi Lavanya

      XSLT is commonly used to transform XML documents to other XML documents, or even HTML or plain text. You can use XSLT if the input & output formats are as mentioned. If they are not, then you will have to go for Groovy scripts.

      Regards

      Eng Swee

      Author's profile photo Former Member
      Former Member

      Great Post..!
      I am not able to access my .xml file that i have kept in src.main.resources folder.
      I am trying to access it from my script.gsh which is kept in src.main.resources.script folder.

      Please let me know how can i access my .xml file.

      Thanks in advance

      Author's profile photo Former Member
      Former Member

      Great post!

      How are you able to run the Groovy code directly in Eclipse?

      Thanks!

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      You need to install the Groovy-Eclipse plugin

      https://github.com/groovy/groovy-eclipse/wiki

       

       

      Author's profile photo Manikandan Shanmugam
      Manikandan Shanmugam

      Hi Eng,

      The post is really helpful to understand how to use groovy in HCI , however i have a requirement to replace a attribute in xml, can you please let me know how to achieve it? attribute lang should be changed as xml:lang

       

      Input:

        <?xml version="1.0" encoding="UTF-8"?>
          <root>
          <Description lang="en">TEST</Description>
          <Forecast>
          <Period endDate="2016-09-01T23:59:59+02:00" startDate="2016-09-01T00:00:00+02:00"/>
          <ForecastQuantity quantity="34.0">
          <name lang="en">TEST1</name>
          <UnitOfMeasure>EA</UnitOfMeasure>
          </ForecastQuantity>
          </Forecast>
          </root> 
      
      
      Output:
      
      
        <?xml version="1.0" encoding="UTF-8"?>
      
          <root>
          <Description xml:lang="en">TEST</Description>
          <Forecast>
          <Period endDate="2016-09-01T23:59:59+02:00" startDate="2016-09-01T00:00:00+02:00"/>
          <ForecastQuantity quantity="34.0">
          <name xml:lang="en">TEST1</name>
          <UnitOfMeasure>EA</UnitOfMeasure>
          </ForecastQuantity>
          </Forecast>
          </root>
      Regards,
      Mani
      
      Author's profile photo Former Member
      Former Member

      Hi Eng,

      I need to create multiple nodes in a HCI mapping. I want to do this with Groovy script, the same way you can do this in PI in a UDF (returning an array via results.addvalue), but I can't get it to work. Do  you have any experience with this?

       

      Cheers,

      Frank

       

      Author's profile photo Jay Malla
      Jay Malla

      Hi Eng Swee Yeoh,

      I have installed the Groovy plug in for Eclipse.  Is there a way to simply run the Groovy scripts developed in HCI through Eclipse easily?  Is there a jar I can add to the build path so the following import works?

      import com.sap.gateway.ip.core.customdev.util.Message;

      In our use case, we have a very complex Groovy script in HCI.  We would like to test just this map by itself in Eclipse by passing in the message and test our logic without running the entire flow.

      Thanks,

      Jay

       

       

       

      Author's profile photo T. van Rooijen
      T. van Rooijen

      Hi Eng Swee,

       

      I'm a bit at a loss on how to incorporate this in the standard groovy script.

      I assume I need to get the message body first, so use the

      'def Message processData(Message message) { '  statement first.

       

      But after that I am no longer allowed to use the Public Void statement.

      So how do I incorporate this in a normal CPI grooy script?

       

      Thanks

      Tom

      Author's profile photo T. van Rooijen
      T. van Rooijen

      I succeeded after only umpteen tries and on the route really learned what a node object was..

       

      import com.sap.gateway.ip.core.customdev.util.Message;
      import groovy.json.*;
      import groovy.util.*;
      import groovy.xml.*;
      import com.sap.gateway.ip.core.customdev.util.Message;
      import org.codehaus.*;
      import java.util.HashMap;
      def Message processData(Message message) {
      
      //Properties
      	def pMap = message.getProperties();
      	def Period_Start_Date_ext = pMap.get("Date_d_execution_depuis_le");
      	def Period_End_Date_ext = pMap.get("Date_d_execution_jusquau");
          
      //Body
          def body_xml= message.getBody(java.lang.String) as String;
      	Node root = new XmlParser().parseText(body_xml);
      	
          root.appendNode("period_start_date", [:], Period_Start_Date_ext);
      	root.appendNode("period_end_date", [:], Period_End_Date_ext);
      	
      	def xml = XmlUtil.serialize(root);
      	message.setBody(xml); 
      
      return message;
      
      }
      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      Well done! Learning things the hard way is always the best teacher, IMHO!

      Author's profile photo Reenu Bairi
      Reenu Bairi

      Hi Eng Swee Yeoh

      In current CPI web UI, where can I see the Console output?

      Thanks,

      Mary Jose

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      Hi Mary

       

      You can download the CP Default Trace from System Log Files and view it there, but it doesn't have the nicest view.

       

      Regards

      Eng Swee

      Author's profile photo Jonathan Ma
      Jonathan Ma

      Thanks for the blog. Can you write the code on how to traverse a more complicated structure, eg:

      <?xml version='1.0' encoding='UTF-8'?>
      <Records>
      <Line>
      <Field>ABC</Field1>
      <Field>123</Field2>
      <Field>XXX</Field3>
      <Field>567890</Field4>
      </Line>
      <Line>
      <Field>ABC1</Field1>
      <Field>1234</Field2>
      <Field>XXXX</Field3>
      <Field>123567890</Field4>
      </Line>
      </Records>

      Thanks Joanthan.