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
Thank you Eduard.
💡 This article is considered as InterSystems Data Platform Best Practice.
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.