Skip to Content
Author's profile photo Thomas Schneider

How to Parse a String in JSON Format in ABSL

I received a couple of questions on how to handle a String in JSON Format in ABSL. You can, for example, call a REST service (see for example Integration of SAP OnDemand Products with Business Suite via REST/OData Services) and the result is a response in JSON. In contrast to a REST service, a SOAP service that always comes with a service description (WSDL) and from this, SAP Cloud Application Studio generate a data type and a transformation from the message into the data type (see External Web Service Integration in SAP Cloud Application Studio). For a REST service a formal service definition (WSDL) is typically not available. The response of the REST service is a string, for example in JSON format (or in XML or other format.

The following code snippet shows how you can parse a string in JSON format into a hierarchical table. Then, of course, you have to loop over the table and find the business content that you are interested in.

Please note, that I do not give the guarantee, that the code can handle all kind of JSON (for example, I did not consider escape characters). But if you find some cases that are not considered by my code, you can easily enhance and improve it and adopt it to you concrete web service.

The code makes use of the FindRegex() function. You can find the documentation on this service and more services for string handling in the studio documentation (http://help.sap.com/studio_cloud). You can find additional information on regular expression in the internet (for example search for “ABAP”+”find”+”regex”. The scripting language of SAP Cloud Application Studio uses the same library for handling regular expression as ABAP).

As a prerequisite, define a business object node (WebServiceParser.Result) that represents a hierarchcial table. (In the coding below, the data type defined by this node is used in lines 10 and 11.  You do not habe to use this BO node itself, but it is required to define the data type.

node Result [0,n] {
 element ID : IntegerValue;
 element ParentID : IntegerValue;
 element Name : LANGUAGEINDEPENDENT_EXTENDED_Name;
 element Value : LANGUAGEINDEPENDENT_EXTENDED_Name;
}

The parsing works with the following ABSL code:

var json = this.Response;
var i = 0;
var i0 = 0;
var controlTag = ""; var controlTag2;
var lastControlTag;
var noOpenObjects = 0; // for checking check only
var noOpenArrays = 0; // for checking check only
var afterColon = false;
var string;
var result : elementsof WebServiceParser.Result;
var results : collectionof elementsof WebServiceParser.Result;
var ID = 0;
var parentID = 0;
while (i<json.Length()){
 i = json.FindRegex("\\{|\\}|\\[|\\]|\"|:|,|\\d+|true|false", i);
 if (i < 0) {
  raise Message.Create("E", "Parsing error (control tag not found)"); break; // *** Error ***
 }

 lastControlTag = controlTag;
 controlTag = json.Substring(i,1);
 switch (controlTag) {
 case "{" , "}", "[", "]", ","  {
  i = i + 1;
  switch (controlTag) {
  case "{" {
   noOpenObjects = noOpenObjects + 1;
   parentID = ID;
  }
  case "}" {
   noOpenObjects = noOpenObjects - 1;
  // lookup for "grandparent ID" -> parentID
   if (!(parentID == 0)) {
    var partentIDtab = results.Where(n=>n.ID == parentID);
    if (partentIDtab.Count() == 1) {
     parentID = partentIDtab.GetFirst().ParentID;
    }
    else {
     raise Message.Create("E", "Parsing error (parentID not found)"); break; // *** Error ***
    }
   }
  }
  case "[" {
   noOpenArrays = noOpenArrays + 1;
   parentID = ID;
  }
  case "]" {
   noOpenArrays = noOpenArrays - 1;
  // lookup for "grandparent ID" -> parentID
   if (!(parentID == 0)) {
    var partentIDtab = results.Where(n=>n.ID == parentID);
    if (partentIDtab.Count() == 1) {
     parentID = partentIDtab.GetFirst().ParentID;
    }
    else {
     raise Message.Create("E", "Parsing error (parentID not found for array)"); break; // *** Error ***
    }
   }
  }
  } 
  // close old node and open new one with exception list
  if ( (controlTag == "," && (lastControlTag == "}" || lastControlTag == "]")) ) {
   // no new node required
  }
  else {
   if( ID > 0 ) {results.Add(result);}
   ID = ID + 1;
   result.ID = ID;
   result.ParentID = parentID;
   result.Name = "";
   result.Value = "";
  }
  afterColon = false;
 }  // end case "{" , ",", "}"
 case ":" {
  if (afterColon) {
   raise Message.Create("E", "Parsing error (open colon)"); break; // *** Error ***
  }
  afterColon = true;
  i = i + 1;
 }
 case "\"" {
  i = i + 1;
  i0 = i;
  i = json.FindRegex("\\{|\\}|\\[|\\]|\"", i);
  if (i < 0) {
   raise Message.Create("E", "Parsing error (control tag not found after quote)"); break; // *** Error ***
  }
  controlTag2 = json.Substring(i,1);
  if (controlTag2 == "\"") {
   string = json.Substring(i0, i-i0);
   if (!afterColon) {   // before colon -> name
    result.Name = string;
   }
   else {// after colon -> value
    result.Value = string;
    afterColon = false;
   }
  }
  else {
   raise Message.Create("E", "Parsing error (quote not closed)"); break; // *** Error ***
  }
  i = i + 1;
 }
 case "t", "T" {
  if (!afterColon) {
   raise Message.Create("E", "Parsing error (true/false)"); break; // *** Error ***
  }
  result.Value = "true";
  afterColon = false;
  i = i + 4;
 }
 case "f", "F" {
  if (!afterColon) {
   raise Message.Create("E", "Parsing error (true/false)"); break; // *** Error ***
  }
  result.Value = "false";
  afterColon = false;
  i = i + 5;
 }
 default {
  // implementation for numeric (\d in regex)
  if (!afterColon) {
   raise Message.Create("E", "Parsing error (numeric before colon)"); break; // *** Error ***
  }
  i = i + 1;
  i0 = i - 1;
  i = json.FindRegex("\\{|\\}|\\[|\\]|\"|:|,|true|false", i);
  if (i < 0) {
   raise Message.Create("E", "Parsing error (numeric: end not found)"); break; // *** Error ***
  }
  controlTag2 = json.Substring(i,1);
  if (controlTag2 == "}" || controlTag2 == ",") {
   string = json.Substring(i0, i-i0);
   result.Value = string;
   afterColon = false;
  }
  else {
   raise Message.Create("E", "Parsing error (numeric end not correct)"); break; // *** Error ***
  }
 }
 }

 // check
 if (noOpenObjects < 0 || noOpenArrays < 0) {
  raise Message.Create("E", "Parsing error (error during object/array processing) (1)");  // *** Error ***
 }

}
// final check
if (!(noOpenObjects == 0) && !(noOpenArrays == 0) && !(parentID == 0)) {
 raise Message.Create("E", "Parsing error (error during final check"); // *** Error ***
}

Assigned Tags

      14 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Sunil Kumar Maurya
      Sunil Kumar Maurya

      Thank You Thomas... this post is a great help for the developer.

      could you please also give some more details on the pattern of true|false in pattern

      "\\{|\\}|\\[|\\]|\"|:|,|\\d+|true|false".

      Author's profile photo Thomas Schneider
      Thomas Schneider
      Blog Post Author

      In JSON, you specify boolean values as true or false w/o quotation marks.

      The FindRegex function finds these.

      Author's profile photo Former Member
      Former Member

      Hi Thomas,

      For completeness, I would suggest to also add the keyword 'null' to the regex-list as well as a respective section for 'null' to the token-case selection.

      But apart from this:

      Thanks for sharing, it removed the need to implement a JSON-Parser myself for the current project.

      However due to legal reasons I have to ask:

      How about copyright? May we use the code in other custom projects?

      Best regards,

      Ludger Bünger

      --

      Custom Development with all4cloud.de

      Author's profile photo Allen Yao
      Allen Yao

      Thank you Thomas, this is a great help for us.

      Author's profile photo Former Member
      Former Member

      Hi Thomas,

      in my implementation WebServiceParser is not found. Which import do I have to include?

      Author's profile photo Sunil Kumar Maurya
      Sunil Kumar Maurya

      Hi Chris

      WebServiceParser is custom BO, I think Thomas use this name only for example purpose. 

      Author's profile photo Former Member
      Former Member

      Hi Sunil,

      thank you for your quick reply. Do you know some developer specific documentation about which data types etc. are available or how to build a loop and so on in the scripting language of the cloud development studio?

      Thank you for your help kind regards,

      Chris

      Author's profile photo Sunil Kumar Maurya
      Sunil Kumar Maurya

      You can find the documents in https://help.sap.com/studio_cloud

      you can download and read online version

      Author's profile photo Former Member
      Former Member

      Hi Thomas,

      I try to understand the code and have two questions:

      1. In line 62, you prevent creation of a new node only if the control tag is a comma. However, how do you detect the situation if there are two ending braces (e.g. {"value": {"subvalue":"subcontent"}} )? Currently (from my understanding) this will create an emtpy entry. Multiple levels will probably create even more entries.
      2. In line 85, you regex for {, }, [, ], and "
        Why do you also look for braces and not only for the quote?
        From my unterstanding -since you are inside a quote already- looking for braces would case issues if there is a brace as value, e.g. something like "{".

      Best regards,

      Ludger Bünger

      --

      Custom Development with all4cloud.de

      Author's profile photo Thomas Schneider
      Thomas Schneider
      Blog Post Author

      Hi Ludger,

      sorry, this is long time ago and from just looking ate the code, I cannot say if you are right. I am quite sure that I tested at least the first case, but I do not remember correctly. As I not longer working for ByDesign, I cannot check this.

      Best regards,

      Thomas

      Author's profile photo Aleksei BELOUSOV
      Aleksei BELOUSOV

      Thank you Thomas ,

      Great job!

      Best wishes,

      Aleksei Belousov

      Author's profile photo Swathi Laxmi
      Swathi Laxmi

      Hello,

      Can you please brief on where the second  code is attached ? Also Response , message etc are throwing errors.

      Author's profile photo David Ordás Pacios
      David Ordás Pacios

      Thank you Thomas, this is a great help for developers.

      Author's profile photo Anantharaj Sivalingam
      Anantharaj Sivalingam

      Hello Experts,

       

      Please help me

      https://answers.sap.com/questions/13460987/how-to-use-regular-expression-in-find-and-replace.html

      Thanks in advance,

      Ananth