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;