Correspondence between a JSON string and an EGL variable

This topic describes the EGL record that corresponds to a JavaScript Object Notation (JSON) string. Other topics describe the functions—serviceLib.convertFromJSON() and serviceLib.convertToJSON()—that are used by a Rich UI developer to convert JSON data to or from a variable, as may be necessary to access a third-party REST service. A failure in either function causes a RuntimeException.

JSON and EGL records

You can define a record to use when accessing a JSON string such as the following one:
{ "EmpNo":10,"LastName":"Smith" }  
Within the brackets of a JSON string, each identifier-and-value pair (such as "Empno":10) is the name and value of a JSON field. To create a record part that matches the JSON string, ensure that each field name in the record part exactly matches (in character and case) each corresponding field name in the JSON string, as shown in the following example:
Record MyRecordPart
   EmpNo INT;
   LastName STRING;
end

You can use any primitive type other than BLOB or CLOB. An EGL record field is also valid if based on a DataItem part that is, in turn, based on one of the supported primitive types.

The EGL propertyJSONName lets you work with a JSON string in which a field name is an EGL reserved word or is not valid in EGL. Here is a variation of the example JSON string:
{ "Emp-No":10,"LastName":"Smith" }  
The problem in this case is that you cannot create an EGL record-field name that includes a hyphen. However, you can use the property JSONName to retain the JSON field name in the Record part, as shown here:
Record MyRecordPart
   EmpNo INT {JSONName = "Emp-No"};
   LastName STRING;
end

(You cannot override the value of JSONName when you declare a record that is based on the Record part.)

In many situations, the record you use to access a JSON string includes records. However, when you are using records and invoke serviceLib.convertFromJSON() or serviceLib.convertToJSON(), you reference only a single record, which is based on the topmost (most inclusive) record part of all the record parts needed. For example, the following JSON string might be returned from a getTime service that calculates the number of seconds since January 1, 1970:
{"Result":{"aTimestamp":1191871152}}

A general rule is that each bracketed clause in the JSON string is the content of a runtime JSON object, which is equivalent to an EGL record.

In the current example, you need to define two record parts. The record you would use in serviceLib.convertFromJSON() or serviceLib.convertToJSON() is based on the following part, which has a field called Result:
Record MyTopPart
   Result MyTimestampPart;
end
Given the structure of the JSON string, the next record part has a field named aTimestamp:
Record MyTimestampPart
   aTimestamp BIGINT;
end

As shown, each JSON identifier (which precedes a colon) requires the presence of a field in a record. If a JSON field name is an EGL reserved word (for example, "TimeStamp"), you must access serviceLib.convertFromJSON() or serviceLib.convertToJSON() by using a dictionary rather than a record. We show this variation later in this topic.

Here is another example, which (although reformatted for readability) is from http://json.org/, a website that describes JSON in detail:
{"Menu": 
  { "id": "file", "value": "File", "popup": 
     {"Menuitem": 
       [
         {"value": "New", "onClick": "CreateNewDoc()"},
         {"value": "Open", "onClick": "OpenDoc()"},
         {"value": "Close", "onClick": "CloseDoc()"}
       ]   
     }
  }
}

(At this writing, that example and others are at http://json.org/example.html.)

The topmost (most inclusive) record part includes a field named Menu:
Record MyTopPart
   Menu MyMenuPart;
end
To build the other record parts, we consider each bracketed clause in the JSON string. The next record part (MyMenuPart) includes fields named id, value, and popup:
Record MyMenuPart
   id STRING; 
   value STRING;
   popup MyPopupPart;
end
The next record part includes an array named MenuItem:
Record MyPopupPart
   MenuItem MyElementPart[];
end
The last record part includes fields named value and onClick:
Record MyElementPart
   value STRING; 
   onClick STRING;
end

To further explore how to use a record when accessing a JSON string, see the Rich UI sample geocode.records.

JSON and EGL dictionaries

An EGL dictionary contains a set of entries, each comprising both a key and a value of any type, as in the following variable declaration:
myRef Dictionary 
{ 
   ID = 5,
   lastName = "Twain",
   firstName = "Mark"
};

You interact with the dictionary as described in "Dictionary part" and related topics in the EGL help system.

The following JSON string might be returned from a getTime service that calculates the number of seconds since January 1, 1970:
{"Result":{"aTimestamp":1191871152}}
You can decide to translate the JSON string (from the leftmost to the rightmost bracket) to a dictionary named myTime, which is declared without detail:
myTime Dictionary;

A general rule is that each bracketed clause in the JSON string is equivalent to an EGL dictionary. In relation to our example JSON string, the function serviceLib.convertFromJSON() treats the symbol at the left of the first colon (:) as the key of a dictionary entry. The key is Result, which is case sensitive. Here (as in all cases) the content to the right of a colon is the value associated with the key whose name is at the left of the colon.

The embedded brackets indicate that the value of Result is an anonymous dictionary. As before, the colon within those brackets distinguish between a key (aTimestamp) and a value (1191871152). In short, you can think of the output of the function serviceLib.convertFromJSON() as follows:
myTime Dictionary 
{ 
   Result = new Dictionary{ aTimestamp = 1191871152 }
};   
You can access the content of aTimestamp by using dotted syntax:
numberOfSeconds BIGINT = myTime.Result.aTimestamp;
On occasion, dotted syntax is not valid. The Yahoo getTime service, for example, returned the following content, including the EGL reserved word Timestamp:
{"Result":{"Timestamp":1191871152}}
To access a value whose key is an EGL reserved word, you must use bracket syntax. The following EGL code is valid for the data returned from the Yahoo getTime service:
numberOfSeconds BIGINT = myTime.Result["Timestamp"];
Here again is the Menu example from http://json.org/:
{"Menu": 
  { "id": "file", "value": "File", "popup": 
     {"Menuitem": 
       [
         {"value": "New", "onClick": "CreateNewDoc()"},
         {"value": "Open", "onClick": "OpenDoc()"},
         {"value": "Close", "onClick": "CloseDoc()"}
       ]   
     }
  }
}

In this example, the dictionary has a single entry whose key is named Menu. The value associated with that key is an anonymous dictionary, as indicated by the brackets that embed the string "id" and all the strings that follow. That anonymous dictionary includes the keys id, value, and popup, along with the values of those keys. You may never have the kind of complexity introduced by the key called popup, but the problem is workable. You can see the relationships in the example JSON string.

Here is a question for you to consider: What statement is necessary to access the string "OpenDoc()", assuming that the function serviceLib.convertFromJSON() has copied the previous JSON string to a dictionary called myMenu?

The answer is as follows:
myString STRING = myMenu.Menu.popup.MenuItem[2].onClick;
The following EGL dictionary reflects the current example:
myMenu Dictionary
{  Menu = new Dictionary
   { id = "file",
     value = "File",
     popup = new Dictionary 
     { MenuItem = new Dictionary[]
       { new dictionary {value = "New", onClick = "CreateNewDoc()" },
         new dictionary {value = "Open", onClick = "OpenDoc()" },
         new dictionary {value = "Close", onClick = "CloseDoc()"}
       } 
     } 
   }
};     
To work with the function serviceLib.convertToJSON(), begin by creating a dictionary that is structured as shown in the previous examples. The following two rules apply:
  • Each dictionary in a hierarchy of dictionaries is equivalent to a bracketed clause in the JSON string
  • Each key is assigned a primitive value, a dictionary, a record, or an array of dictionaries or records.

To further explore how to use a dictionary record when accessing a JSON string, see the Rich UI sample geocode.dictionaries.

JSON and both records and dictionaries

You can mix records and dictionaries in the following cases:
  • When you prepare to invoke serviceLib.convertFromJSON() with a record
  • When you prepare to invoke serviceLib.convertToJSON() with a record or dictionary
You might include a dictionary in a record to access the following JSON string:
{"Result":{"Timestamp":1191871152}}
You can define the following part:
Record ResultRecordPart
   Result Dictionary;
end
Your code can access the timestamp value as follows:
   myResult ResultRecordPart;
   milliseconds BIGINT;
		serviceLib.convertFromJSON(resp.body, myResult);
		milliseconds = myResult.Result["Timestamp"] as BIGINT;
A general rule is that, if you associate an incoming JSON clause with a dictionary, you can access data within the clause only by using a dictionary syntax. A complex example is as follows:
{"Menu": 
  { "id": "file", "value": "File", "popup": 
     {"Menuitem": 
       [
         {"value": "New", "onClick": "CreateNewDoc()"},
         {"value": "Open", "onClick": "OpenDoc()"},
         {"value": "Close", "onClick": "CloseDoc()"}
       ]   
     }
  }
}
To prepare to access the content, you can define the following parts:
Record MyTopPart
   Menu MyMenuPart;
end

Record MyMenuPart
   id STRING; 
   value STRING;
   popup Dictionary; 
end
The following EGL dictionary reflects the structure named popup:
   popup Dictionary 
   { MenuItem = new Dictionary[]
      { new Dictionary {value = "New", onClick = "CreateNewDoc()" },
        new Dictionary {value = "Open", onClick = "OpenDoc()" },
        new Dictionary {value = "Close", onClick = "CloseDoc()"}
      } 
   } 

(We show that dictionary for illustration. The substructure of a Dictionary may be useful when you are invoking serviceLib.convertToJSON(), but is not used when you are invoking serviceLib.convertFromJSON() .)

The following code accesses the string "OpenDoc()":
   myTop MyTopPart;
   itemString STRING;
   serviceLib.convertFromJSON(resp.body, myTop);
   itemString = myTop.Menu.popup.MenuItem[2].onClick;