· Jun 23

Iterating Through and Accessing Nested JSON Values


I'm trying to figure out why I'm unable to iterate through a dynamic array and access the nested objects.

Using the NHS PDS FHIR API in the NHS sandbox environment, I'm querying the PDS endpoint using a sample NHS Number to retrieve a patient's demographics. My Business Operation reads the response data and passes it back to my Business Process where I intend on iterating through certain nested objects. The data present in these nested objects will decide what happens next in the process.

In the JSON snippet below, I'm attempting to access the values of code and display.

"meta": {
        "versionId": "2",
        "security": [
                "system": "",
                "code": "U",
                "display": "unrestricted"

I am able to get the security array but unsure how to get the value of the keys within that. I've attempted iterating through and using %Get().


PDSINTEGRATION>zw securityArray
securityArray=[{"system":"","code":"U","display":"unrestricted"}]  ; <DYNAMIC ARRAY>

PDSINTEGRATION>set iterator=securityArray.%GetIterator()                                            

PDSINTEGRATION>while iterator.%GetNext(.key,.val) { write !, "Element index: "_key_", value: "_val }
Element index: 0, value: 117@%Library.DynamicObject
PDSINTEGRATION>zw securityArray.%Get("code")                                                        
{"system":"","code":"U","display":"unrestricted"}  ; <DYNAMIC OBJECT>



Product version: IRIS 2023.1
Discussion (4)2
Log in or sign up to continue

Maybe there are tools to dump a dynamic object, I don't know, but you can always write your own short method

/// obj: a dynamic object
/// opt: an option, how to display array elements
///      0: just show the index number
///      1: show the parenthesized index
///      2: show index number in a %Get() method
/// tag: optional, the name of the <obj> variable
ClassMethod DumpJSON(obj, opt = 2, tag = "")
	set itr=obj.%GetIterator(), arr=obj.%IsA("%DynamicArray") set:tag]"" tag=tag_"."
	while itr.%GetNext(.key, .val) {
		set:arr key=$case(opt, 2:"%Get("_key_")", 1:"("_key_")", :key)
		if $isobject(val), val.%IsA("%DynamicAbstractObject") {
			do ..DumpJSON(val,opt,tag_key)
		} else { write tag,key,": ",val,! }

For ease of use, put it into the %ZLANGC00.mac, for example

%ZLANGC00   ; Command extensions

// Dump a dymanmic object
ZDDUMP(obj,opt,tag) Public { do ##class(your.utility).DumpJSON(obj,.opt,.tag) }

For the data, you mentioned above, the following will be displayed

set metaDynObj={"versionId":"2","security":[{"system":"http://terminol....}

zddump metaDynObj::"metaDynObj"
metaDynObj.versionId: 2 U unrestricted

zddump [11,22,33]
0: 11
1: 22
2: 33

zddump [11,22,33]:1:"x"
x.(0): 11
x.(1): 22
x.(2): 33

Warning: what I describe here is not part of any released IRIS version. It is still in development and details might change.

We are working on an implementation of something we call "ASQ". This is intended to be a superset of the ISO Standard "JSON Path Language" (JPL). I suspect our current implementation will not meet all of your requirements but perhaps you will find this interesting:

USER>set obj = {"meta":{"versionId":"2","security":[{"system":"","code":"U","display":"unrestricted"}]}}

USER>zw obj.apply("$[*][*].system")

We can repeat this same pattern but remove the security field value's enclosing array and we see the same result:

USER>set obj = {"meta":{"versionId":"2","security":{"system":"","code":"U","display":"unrestricted"}}}

USER>zw obj.apply("$[*][*].system")

Of course there is more, much more. I have more complex examples if you are interested.