Copying a JSON string to and from an EGL variable

You can define an EGL record that corresponds to a JavaScript™ Object Notation (JSON) string. Rich UI developers use the serviceLib.convertFromJSON and serviceLib.convertToJSON functions to convert JSON data to or from a variable, as might be necessary to access a third-party REST service. A failure in either function causes a RuntimeException. For detailed information about those functions, see the related links at the end of this topic.

JSON and EGL records

You can define a record to use when you access a JSON string, such as the following example:
{ "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:
Record MyRecordPart
   EmpNo INT;
   LastName STRING;
end

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

You can use the JSONname EGL property to work with a JSON string in which a field name is an EGL reserved word or is not valid in EGL. This example is a variation of the example JSON string:
{ "Emp-No":10,"LastName":"Smith" }  
In this case, you cannot create an EGL record-field name that includes a hyphen. However, you can use the JSONname property to retain the JSON field name in the Record part, as shown here:
Record MyRecordPart
   EmpNo INT; {JSONname = "Emp-No"}
   LastName STRING;
end
In many situations, the record that 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 one record, which is based on the topmost (most inclusive) record part of all of 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 equivalent to an EGL record. In the current example, you must 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 a field to be in a record. If a JSON field name is an EGL reserved word, such as "TimeStamp", you must access serviceLib.convertFromJSON or serviceLib.convertToJSON by using a dictionary rather than a record. This variation is shown later in this topic.

This example is from http://json.org/, which is a Web site that describes JSON in detail:
{"Menu": 
  { "id": "file", "value": "File", "popup": 
     {"Menuitem": 
       [
         {"value": "New", "onClick": "CreateNewDoc()"},
         {"value": "Open", "onClick": "OpenDoc()"},
         {"value": "Close", "onClick": "CloseDoc()"}
       ]   
     }
  }
}
The topmost, or most inclusive, record part includes a field named Menu:
Record MyTopPart
   Menu MyMenuPart;
end
To build the other record parts, 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 you access a JSON string, see the Rich UI sample geocode.records.

JSON and EGL dictionaries

An EGL dictionary contains a set of entries, which are each composed of 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 help contents.

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;

Each bracketed clause in the JSON string is equivalent to an EGL dictionary. In relation to the 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. The content to the right of a colon is the value that is 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. The colon within those brackets distinguishes between a key (aTimestamp) and a value (1191871152). You might 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;
Dotted syntax is not always valid. For example, the Yahoo getTime service returns the following content, including the EGL reserved word Timestamp:
{"Result":{"Timestamp":1191871152}}
To access a value whose key is an EGL reserved word, use bracket syntax. The following EGL code is valid for the data that is 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 one entry whose key is named Menu. The value that is 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, and the values of those keys. You might 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.

Consider this: 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 serviceLib.convertToJSON function, begin by creating a dictionary that is structured as shown in the previous examples. 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 you access 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;
If you associate an incoming JSON clause with a dictionary, you can access data within the clause only by using a dictionary syntax:
{"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()"}
      } 
   } 
Note: It might be helpful to know the substructure of a Dictionary when you invoke serviceLib.convertToJSON.
The following code accesses the string "OpenDoc()":
   myTop MyTopPart;
   itemString STRING;
   serviceLib.convertFromJSON(resp.body, myTop);
   itemString = myTop.Menu.popup.MenuItem[2].onClick;

Feedback