我有这个 json 文件:
[
{
"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"
}
}
}
]
我需要映射所有包含@id 的对象,因此用映射的相关@id 值替换所有@ref 值。我想获得这个:
[
{
"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"
}
}
}
]
我正在使用此类来替换值:
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 and Replace
*/
func findAndReplace (json: JSON) -> JSON {
findJSOGids(json)
let replaced = replaceJSOGrefs(json, ids: ids)
return replaced
}
/*
* Find "@id" keys and map values related
*/
func findJSOGids (value: JSON) {
for (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 with 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> ()
for (key, subJson): (String, JSON) in value {
if (key == "@ref") {
let mValueForKey = value[key].stringValue
var isReplaced = false
while (isReplaced == false) {
for (idKey, _): (String, JSON) in ids[mValueForKey]! {
if (idKey == "@ref") {
print("found a @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]()
for (_, subJson): (String, JSON) in value {
result.append(replaceJSOGrefs(subJson, ids: ids))
}
return JSON(result)
} else {
return value
}
}
}
它可以工作,但它会遗漏一些 @ref 值。
有人可以帮帮我吗?
提前致谢。
编辑
我正在使用 ObjectMapper映射对象。
最佳答案
我认为查找替换方法不会那么有效,因为您必须对数据进行多次传递(直到找不到任何 @ref
字符串)。
您可能应该利用这样一个事实,即您的 JSON 模型引用类型语义(与值类型相反)并照此解析它,将解析对象中的 @ref
作为错误引用保留。您解析的每个对象都应该添加到可以被 @id
引用的缓存中。然后在第二遍中,您将通过缓存重新连接每个引用,以使用您刚刚构建的缓存作为查找表。
如果每个模型都实现以下协议(protocol)
protocol RefObject {
func updateReferences(using cache: [String: RefObject])
}
您可以为每个模型实现它,以便每个模型类都有一个自定义的重新布线逻辑。以下是此类模型类的几个示例:
对于仅由 JSON 中的 {"@ref": "xxx"}
表示的通配符,我将创建一个指针类,它只指向所引用的对象。
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]
}
}
对于一个人你可以实现类似的东西
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 }
}
}
(假设 person 可以有 {"id": "xx", "name": "xx", "other": {"@ref": "xx"}}
其中"other"是other
是可选的
这是一种通用方法而不是特定的实现,但它会根据您的需要非常特定于领域。
更新 有一个类似的协议(protocol)叫JSON API (具有误导性的名称 IMO,但它使用通过 id 引用 JSON 对象的相同方法)。这是 Swift 中的一个实现:https://github.com/wvteijlingen/spine可能值得一试
关于swift - 递归函数替换json对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38187343/