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 JSONLib.convertFromJSON and JSONLib.convertToJSON functions, which are used by a Rich UI developer to convert JSON data to or from a variable, as might be necessary to access a third-party REST service.

JSON and EGL records or handlers

You can define a Record or Handler type 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 type that matches the JSON string, ensure that each field name in the Record type 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 type that is, in turn, based on one of the supported primitive types.

The EGL annotationJSONName 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 type, 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 type.)

In many situations, the record you use to access a JSON string includes records. However, when you are using records and invoke JSONLib.convertFromJSON or JSONLib.convertToJSON, you reference only a single record, which is based on the topmost (most inclusive) Record type of all the Record types 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 types. The record you would use in JSONLib.convertFromJSON or JSONLib.convertToJSON is based on the following type, which has a field called Result:
Record MyTopPart
   Result MyTimestampPart;
end
Given the structure of the JSON string, the next Record type 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 JSONLib.convertFromJSON or JSONLib.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 type includes a field named Menu:
Record MyTopPart
   Menu MyMenuPart;
end
To build the other Record types, we consider each bracketed clause in the JSON string. The next Record type (MyMenuPart) includes fields named id, value, and popup:
Record MyMenuPart
   id STRING; 
   value STRING;
   popup MyPopupPart;
end
The next Record type includes an array named MenuItem:
Record MyPopupPart
   MenuItem MyElementPart[];
end
The last Record type includes fields named value and onClick:
Record MyElementPart
   value STRING; 
   onClick STRING;
end

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"
};
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 JSONLib.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 JSONLib.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 JSONLib.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 JSONLib.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 all variables

You can mix records or handlers with dictionaries in the following cases:
  • When you prepare to invoke JSONLib.convertFromJSON with a record or handler
  • When you prepare to invoke JSONLib.convertToJSON with a record, handler, or dictionary
You might include a dictionary in a record to access the following JSON string:
{"Result":{"Timestamp":1191871152}}
You can define the following type:
Record ResultRecordPart
   Result Dictionary;
end
Your code can access the timestamp value as follows:
   myResult ResultRecordPart;
   milliseconds BIGINT;
		JSONLib.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 types:
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 JSONLib.convertToJSON, but is not used when you are invoking JSONLib.convertFromJSON .)

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