Cybersecurity
DevOps Cloud
IT Operations Cloud
One useful feature of the ChaiScript engine is the support for JSON. As ModScript can be invoked directly via the Direct URL context, a JSON body could be sent by the caller and ModScript can parse it and then use it. Also, as ModScript can make REST call-outs, the fact that ChaiScript can format JSON for us empowers us to really get things done.
JSON is a convenient format for passing data in a web application as it is compact and well defined. Here is an example:
{ "arrayOfInts": [1,2,3,4,5], "intData": 5, "doubleData": 4.5, "stringData": "Welcome to ModScript" }
In the above JSON sample, the curly braces { ... } indicate the beginning of an object, with name-value pairs. The square braces [ ... ] indicate an array. When the ChaiScript engine parses a JSON string, integers become ints, floating points become doubles, text becomes strings. JSON arrays become Vectors. JSON objects become Maps which can store name-value pairs; it is important that the JSON not have repeating name entries in the same object as Maps can only store unique key values. With this in mind, the following is an ModScript excerpt that will parse the JSON from a string (as the JSON text has embedded quotes, we escape them with backslashes). The following script will write "Welcome to ModScript" as an Information entry in the Application Event Log:
Ext.LogInfoMsg( "{ \"arrayOfInts\": [1,2,3,4,5], \"intData\": 5, \"doubleData\": 4.5, \"stringData\": \"Welcome to ModScript\" }".from_json()["stringData"] );
Step by step:
Ext.LogInfoMsg()
, which will take the output of the inner code and write it to the Application Event Log.from_json()
, which parses the JSON string into a Map (because the outer most part of the JSON is a JSON object).["stringData"]
, which calls the lookup operator on the Map, returning the corresponding entry. In this case, it returns the string "Welcome to ModScript", which is what gets sent to the Ext.LogInfoMsg()
function call.Notes:
from_json()
you will get a Map with a key-value entry where the value is a Map.from_json()
you will get a Vector with a string, an int, and then a Map. As such, the from_json()
function can parse any JSON string, as long as the JSON objects do not have duplicate key names in them.from_json()
may be a Map, Vector, string, int, or double.from_json()
to take a string with comma-separated integers and turn it into a Vector. When working with Multi-Relational, Multi-Selection, or Multi-Group fields, getting the internal value will return a comma-separated list of integers with commas at the beginning and end (example: ",65,732,899,"). Trim these commas, append square braces, and you have a JSON array (example: "[65,732,899]") which from_json()
can parse into a Vector of integers.The ChaiScript Engine also provides a to_json()
function. This can be invoked on a Map, Vector, string, int, or double, and will generate a JSON string from the object. This is very helpful, especially when the scripter is pulling text from various locations, as they do not need to worry about encoding the quotes, etc, while building the JSON string. In a future blog article about using ModScript to invoke REST calls, you will see the creation of the HTTP message body that looks like this:
["fixedFields":false, "fields":[["dbname":"TITLE"], ["dbname":"STATE"]]].to_json()
What you see here is an inline ChaiScript Map (name value pairs created with a : separator). Inside the Map is a "field" entry which is a Vector of Maps. The resulting JSON string:
{ "fields" : [{ "dbname" : "TITLE" }, { "dbname" : "STATE" }], "fixedFields" : false }
Formatting JSON From Variant
The to_json()
utility does not play nicely with Variant. This is mainly because it is not clear what JSON type the Variant should be mapped to: is it a string, an int, a string that contains an int? Due to this ambiguity, there is no easy way to make Variant play nicely with to_json()
. However, Variant has a member method Variant.to_string()
. With this, you can get a string from the Variant, and string has other conversion methods like string.to_int()
, so chaining a Variant "v" as such: v.to_string().to_int()
will give you the value of the Variant as an int. SBM 11.4 introduced many methods to avoid Variant in general, and it also added functions like Variant.to_int()
.
// an example for 11.3.1 Ext.LogInfoMsg( [ Shell.Item().GetFieldValue("TITLE").to_string(), Shell.Item().GetFieldValue("STATE").to_string().to_int() ].to_json() ); // equivalent example for 11.4 Ext.LogInfoMsg( [ Shell.Item().GetFieldValueString("TITLE"), Shell.Item().GetFieldValueInt("STATE") // or Shell.Item().GetFieldValue("STATE").to_int() ].to_json() );
Step by step:
Ext.LogInfoMsg()
, which will take the output of the inner code and write it to the Application Event Log.to_json()
function is invoked on the Vector, creating a JSON string.Ext.LogInfoMsg()
.Notes:
to_json()
does not work with Variant directly (or a Map/Vector which contains a Variant). A Variant can be converted to a string using Variant.to_string()
, and the returned string can then be converted to int using string.to_int()
. SBM 11.4 added functions like Variant.to_int()
and Variant.to_double()
so that the value does not first need to be converted to a string.to_json()
has newlines and white-space, which makes the JSON readable.