用于替换json对象的递归函数

时间:2016-07-04 14:43:05

标签: 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来映射对象。

1 个答案:

答案 0 :(得分:1)

我认为查找替换方法不会有效率,因为您必须对数据进行多次传递(直到找不到任何cd sip-version python configure.py make make install 字符串)。

您应该利用JSON模型引用类型语义(与值类型相反)并将其解析为这样的事实,将解析后的对象中的C:\Python保留为错误引用。您解析的每个对象都应添加到@ref引用的缓存中。然后在第二遍中,您将通过缓存重新布线每个引用,使用您刚刚构建为查找表的缓存。

如果每个模型都实现以下协议

@ref

您可以按模型实现它,以便为每个模型类提供自定义重新布线逻辑。以下是此类模型类的几个示例:

对于JSON中仅由@id表示的通配符,我创建一个指针类,它只会指向引用的对象。

protocol RefObject {
    func updateReferences(using cache: [String: RefObject])
}

对于一个人,你可以实现与

类似的东西
{"@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] } } 其中&#34;其他&#34; 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 } } } 是可选的

这是一种通用的方法,而不是特定的实现方式,但根据您的需要,它可能是特定于域的。

更新有一个名为JSON API的类似协议(误导性名称IMO,但它使用了通过id引用JSON对象的相同方法)。这是Swift中的一个实现:https://github.com/wvteijlingen/spine可能值得一试