swift - Recursive function to replace json objects -
i have json file:
[ { "person": { "@id": "value1", "name": "mattia" }, "person1": { "@ref": "value1" }, "subpersons": [ { "@id": "value2", "name": "luca", "key": { "@ref": "value1" } }, { "@ref": "value1" }, { "@id": "value3", "subsubpersons": [ { "again": { "@ref": "value2" } } ] } ], "key": { "subkey": { "@ref": "value1" } } } ]
i need map objects contains @id replace @ref values related @id values mapped. i'd obtain this:
[ { "person": { "@id": "value1", "name": "mattia" }, "person1": { "@id": "value1", "name": "mattia" }, "subpersons": [ { "@id": "value2", "name": "luca", "key": { "@id": "value1", "name": "mattia" } }, { "@id": "value1", "name": "mattia" }, { "@id": "value3", "subsubpersons": [ { "again": { "@id": "value2", "name": "luca", "key": { "@id": "value1", "name": "mattia" } } } ] } ], "key": { "subkey": { "@id": "value1", "name": "mattia" } } } ]
i'm using class replace values:
import uikit import alamofire import alamofireobjectmapper import objectmapper import swiftyjson import swiftdate import async class findandreplace { var ids = dictionary<string, json>() var dictchanged = dictionary<string, json>() var isdictinit: bool = false /* * find , replace */ func findandreplace (json: json) -> json { findjsogids(json) let replaced = replacejsogrefs(json, ids: ids) return replaced } /* * find "@id" keys , map values related */ func findjsogids (value: json) { (key, subjson): (string, json) in value { if (key == "@id") { let mvalueforkey = value[key].stringvalue ids[mvalueforkey] = value } if (subjson.type == type.dictionary || subjson.type == type.array) { findjsogids(subjson) } } } /* * replace "@ref" keys fields mapped in ids */ func replacejsogrefs (var value: json, var ids: dictionary<string, json>) -> json { if (value.type == type.dictionary) { var result = dictionary<string, json> () (key, subjson): (string, json) in value { if (key == "@ref") { let mvalueforkey = value[key].stringvalue var isreplaced = false while (isreplaced == false) { (idkey, _): (string, json) in ids[mvalueforkey]! { if (idkey == "@ref") { print("found @ref in dictionary") let dictvaluereplaced = replacejsogrefs(ids[mvalueforkey]!, ids: ids) ids.updatevalue(dictvaluereplaced, forkey: mvalueforkey) } } } return ids[mvalueforkey]! } else { result[key] = replacejsogrefs(subjson, ids: ids) } } return json(result) } else if (value.type == type.array) { var result = [json]() (_, subjson): (string, json) in value { result.append(replacejsogrefs(subjson, ids: ids)) } return json(result) } else { return value } } }
it works misses @ref values.
can please me?
thanks in advance.
edit
i'm using objectmapper map objects.
i think find-replace approach won't efficient since you'll have many passes on data (until can't find @ref
strings).
you should leverage fact json models reference types semantics (as oppose value types) , parse such, keeping @ref
in parsed objects faulted references. every object parse should add in cache can referenced @id
. in second pass you'll go through cache rewiring each reference using cache built lookup table.
if every model implements following protocol
protocol refobject { func updatereferences(using cache: [string: refobject]) }
you can implement per-model have custom rewiring logic per each model class. here few examples of such model classes:
for wildcard represented {"@ref": "xxx"}
in json i'd create pointer class point referred object.
class pointer: refobject { let referredid: string var referred: refobject! init(referedid: string) { self.referredid = referredid } func updatereferences(using cache: [string : refobject]) { self.referred = cache[referredid] } }
for person can implement similar
class person: refobject { let id: string let name: string var otherid: string? var other: person? init(id: string, name: string, otherid: string?) { self.id = id self.name = name self.otherid = otherid } func updatereferences(using cache: [string : refobject]) { other = otherid.flatmap{ cache[$0] as? person } } }
(this assumes person can have {"id": "xx", "name": "xx", "other": {"@ref": "xx"}}
"other" other
optional
this general approach , not particular implementation, domain specific depending on needs.
update there similar protocol called json api (misleading name imo, utilizes same approach of referencing json objects id). here implementation in swift: https://github.com/wvteijlingen/spine might worth checking out
Comments
Post a Comment