%DynamicObject: How to insert json property at a specific location?
Hi,
I know json does not impose any order, but for readability I would like to insert a json property at a specific location at the start of a %DynamicObject, not at the end.
Is there a known way to do that (other than string manipulation)?
Comments
/// Python reorder FHIR properties
ClassMethod PyFHIRResourceReOrder(resource As %String) As %String [ Language = python ]
{
import json
from collections import OrderedDict
result = json.loads(resource, object_pairs_hook=OrderedDict)
result.move_to_end("extension", last = False)
result.move_to_end("meta", last = False)
result.move_to_end("id", last = False)
result.move_to_end("resourceType", last = False)
return json.dumps(result)
}This Python code is what I ended up with. It re-orders the properties "resourceType", "id", "meta" and "extension" to be at the start
String manipulation under covers! ![]()
Yes, although the Python code does deal with an actual collection object :)
If you want to reorder JSON properties (alphabetically or just put some of them at the beginning) then use a utility method, like this, especially if you have several object(types) to reorder
Class DC.Utility Extends %RegisteredObject
{
/// Reorder a JSON Object or Array
///
/// obj: JSON-Object
/// ord: prop1, prop2, ... Desired order for (some) properties
/// (Properties not listed are copied in the order in which they were created)
/// If ord not present, properties will be reordered in aplphabetical order
///
/// obj: JSON-Array
/// ord: pos1, pos2, ... Desired order for (some) array items
/// (Items not listed are copied in ascending order)
///
ClassMethod ReOrder(obj As %DynamicAbstractObject, ord... As %String)
{
i obj.%Extends("%DynamicObject") {
s new={}, itr=obj.%GetIterator()
i '$g(ord) {
while itr.%GetNext(.k) { s done(k)=0 }
s k="" f s k=$o(done(k)) q:k="" d new.%Set(k,obj.%Get(k))
} else {
f i=1:1:$g(ord) { s k=ord(i),done(k)=1 d:$e(obj.%GetTypeOf(k),1,2)'="un" new.%Set(k,obj.%Get(k)) }
while itr.%GetNext(.k,.v) { d:'$d(done(k)) new.%Set(k,v) }
}
} elseif obj.%Extends("%DynamicArray") {
s new=[], itr=obj.%GetIterator(), max=obj.%Size(), done=""
f i=1:1:$g(ord) { s k=ord(i) i k,k<=max d new.%Push(obj.%Get(k-1)) s $bit(done,k)=1 }
while itr.%GetNext(.k,.v) { d:'$bit(done,k+1) new.%Push(v) }
} else { s new=obj }
q new
}
}Some examples
s car={"color":"red", "fuel":"diesel", "maxspeed":150, "maker":"Audi", "model":"Quattro Q5", "power":300, "available":true, "rating":8, "allWheel":true }
s car1=##class(DC.Utility).ReOrder(car) // order all props alphabetically
s car2=##class(DC.Utility).ReOrder(car,"maker","model","available") // start with maker, model, etc.
w car.%ToJSON(),!,car1.%ToJSON(),!,car2.%ToJSON() --->
{"color":"red","fuel":"diesel","maxspeed":150,"maker":"Audi","model":"Quattro Q5","power":300,"available":true,"rating":8,"allWheel":true}
{"allWheel":"1","available":"1","color":"red","fuel":"diesel","maker":"Audi","maxspeed":150,"model":"Quattro Q5","power":300,"rating":8}
{"maker":"Audi","model":"Quattro Q5","available":"1","color":"red","fuel":"diesel","maxspeed":150,"power":300,"rating":8,"allWheel":"1"}Thanks, Julius, that is really helpful!!
I have implemented the part of the method that I needed as follows:
/// Move FHIR resourceproperties in the followin order:
/// - resourceType
/// - id
/// - meta
/// - extension
ClassMethod FHIROrderResourceProperties(resource As %DynamicObject) As %DynamicObject
{
#dim order as %DynamicArray = [ "resourceType", "id", "meta", "extension" ]
#dim newObject as %DynamicObject = {}
for index = 0:1:order.%Size() - 1
{
set element = order.%Get(index)
set done(element) = 1
if $EXTRACT(resource.%GetTypeOf(element), 1, 2) '= "un"
{
do newObject.%Set(element, resource.%Get(element))
}
}
set iterator = resource.%GetIterator()
while iterator.%GetNext(.element, .value)
{
if '$DATA(done(element))
{
do newObject.%Set(element, value)
}
}
return newObject
}