Article
Eduard Lebedyuk · Jan 28, 2019 2m read

Iterate over dynamic object

Here's a sample code to display JSON or dynamic object.

It shows how to iterate over object, get property values and their paths.

Class JSON.Test
{

/// do ##class(JSON.Test).Test()
ClassMethod Test()
{
    set json = "{""a"":1,""b"":2,""c"":{""c1"":3,""c2"":4}, ""d"": [5, {""e_e"":6}, 7]}"
    
    set obj = {}.%FromJSON(json)
    
    do ..Iterate(obj)
}

ClassMethod Iterate(obj As %DynamicAbstractObject, level = 0, path = "obj")
{
    set indent = $j("", level * 4)
    #dim iterator As %Iterator.Array
    set iterator = obj.%GetIterator()
    
    while iterator.%GetNext(.key, .value) {
        set type = obj.%GetTypeOf(key)
        write indent, "Key: ", key, !
        write indent, "Type: ", type, !
        
        if $classname(obj) = "%Library.DynamicArray" {
            set newPath = path _ ".%GetAt(" _ key _ ")"
        } else {
            if $zname(key, 6) = 1 {
                set newPath = path _  "." _ key
            } else {
                set newPath = path _  ".""" _ key _ """"
            }
        }
        
        write indent, "Path: ", newPath, !
        if $isObject(value) {
            write indent, "Value: ", !
            do ..Iterate(value, level + 1, newPath)
        } else {
            write indent, "Value: ", value, !
        }
        write !
    }
}

}

Output from running Test method:

Key: a
Type: number
Path: obj.a
Value: 1
 
Key: b
Type: number
Path: obj.b
Value: 2
 
Key: c
Type: object
Path: obj.c
Value:
    Key: c1
    Type: number
    Path: obj.c.c1
    Value: 3
 
    Key: c2
    Type: number
    Path: obj.c.c2
    Value: 4
 
 
Key: d
Type: array
Path: obj.d
Value:
    Key: 0
    Type: number
    Path: obj.d.%GetAt(0)
    Value: 5
 
    Key: 1
    Type: object
    Path: obj.d.%GetAt(1)
    Value:
        Key: e_e
        Type: number
        Path: obj.d.%GetAt(1)."e_e"
        Value: 6
 
 
    Key: 2
    Type: number
    Path: obj.d.%GetAt(2)
    Value: 7
61
3 8 5 1,566

Replies

This is very neat, thankyou Eduard.

hi, I tried to modify the above ClassMethod iterate using a local variable sessionId inside the while loop.

Doing this I found out, the behavior of this method is not like normal ClassMethods.

The sessionId set in one cycle of the loop in the next cycle is invalid or - if I set  it to a default value before the loop - it has this default value again.

As a temporary solution I then set a global ^SESSIONID and used that inside the loop. In case I kill this global at the end of the method, I have the same effect again. The ^SESSIONID global is undefined inside the loop again.

It looks like my solution is working when I kill the temporary Global outside this method. But this way is needing a lock of the global, which I could avoid if I could use a local variable.

So: Is there a solution for this problem or is this an error in the %DynamicAbstractObject class and I have to live with this behaviour?

Post a minimal code snippet illustrating your issue please.