Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
ThomasSchneider
Product and Topic Expert
Product and Topic Expert

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 ***
}
14 Comments