swift - 递归函数替换json对象

标签 swift function recursion

我有这个 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/

相关文章:

ios - 将背景音乐 ( itunes ) 优先于 avfoundation 播放器节点

javascript - 在没有 setTimeout 的情况下在 JavaScript 中模拟文本键入效果

javascript - 计算 ReactJS 中父评论的线程数

html - 如何将主体类添加到类别及其子类别 [子类别] Genesis Wordpress

python - 随机执行一个函数

c - 从文件中精确打印和扫描 (C)

haskell - C++ 和 Haskell 中的树遍历

swift - 错误 : Type "DetailViewController" does not to protocol VKSdkDelegate

objective-c - 如何将此方法从 Objective-C 转换为 Swift

swift - 不知道如何得到完成结果