· Feb 22, 2020

Convert an array to a JSON string

I need to convert an array with an unknown number of indices to a JSON string for transmission (which is why it isn't possible to iterate through it using $ORDER). Does ObjectScript provide functionality to convert an array to a JSON string?


Edit 1: As Joel mentioned, the array is subscripted and has an arbitrary structure like:


which needs to be converted to

{"1":"a", "3":{"4":"b","6":"c"}, "5":{"6":{"7":"d"}}}

I had considered using a combination of $Query (to traverse the array) and $Order (to retrieve property names) but was wondering if a utility method already exists.


IRIS for UNIX (Apple Mac OS X for x86-64) 2019.4.0DS (Build 165U) Fri Aug 30 2019 00:02:44 EDT

Discussion (6)3
Log in or sign up to continue

If you have old version of Caché, you can use %ZEN.Auxiliary.jsonProvider or %ZEN.Auxiliary.altJSONProvider, which have a bunch of useful methods, for example:

Here are two small examples:

set array=##class(%ListOfDataTypes).%New()
for i=1:1:4000000 array.Insert("item"_i)
write "count = ",array.Count(),!
do ##class(%ZEN.Auxiliary.altJSONProvider).%WriteJSONStreamFromObject(.stream,array,,,1,"aeloq")
; here you can save stream to a file or send it to the client
set meta=$lb("nameA","nameB","nameC")
for i=1:1:4000000 set data(i)=$lb("itemA"_i,"itemB"_i,"itemC"_i)
do ##class(%ZEN.Auxiliary.altJSONProvider).%ArrayToJSON(.meta,.data)

We may need more clarity in order to answer this question. This is what I think you mean. You want to take an ObjectScript array of arbitrary structure, like this:


...and turn it into JSON. But what should the target JSON for this example look like? Something like this?

{"1":"a", "3":{"4":"b","6":"c"}, "5":{"6":{"7":"d"}}}

...or something different?

In any case, to loop through an ObjectScript array of arbitrary structure, you need to use $Query.

I would recommend a different structure to the JSON since an array node can hold both, a value and subnodes. This should be reflected in the JSON. So, for an array:

I suggest to generate an JSON in the form: 


This may not be the most convenient for the receiving end to read, but it can hold the full information from the array. This can easily be created using a recursive procedure:

 /// Converts an arbitrary array into an JSON-Structure returned
/// as %DynamicObject. Subnodes are read recursively, so there 
/// might be a limit tothe number of levels that can be read.
/// Usage example:
/// >set a(1)="A"
/// >set a(1,1)="AA"
/// >set a(1,2)="AB"
/// >set a(1,2,1)="ABA"
/// >set a(1,3,1)="ACA"
/// >set a(2,1)="BA"
/// >set a(3)="C"
/// >set a(3,1)="CA"
/// >write $$^Array2JSON(.a).%ToJSON()
/// {"1":["A",{"1":["AA"],"2":["AB",{"1":["ABA"]}],#
/// "3":[{"1":["ACA"]}]}],"2":[{"1":["BA"]}],"3":["C",{"1":["CA"]}]}
/// I: &array: reference to the array
/// O: JSON: %DynamicObject holding the indices as keys and node
///  values and 
/// subnodes in %DynamicArrays
Array2JSON(&array) Public
set JSON = ##class(%DynamicObject).%New()
set key = $order(array(""))
while ( key'="" )
// create a new entry
set subJSON = ##class(%DynamicArray).%New()
if ( $get(array(key))'="" )
do subJSON.%Push(array(key))
if ( $order(array(key,""))'="" )
kill subarray
merge subarray = array(key)
set subarrayJSON = $$Array2JSON(.subarray)
do subJSON.%Push(subarrayJSON)
do JSON.%Set(key,subJSON)
set key = $order(array(key))
return JSON