2016-07-04 65 views
1

我有这个JSON文件:递归函数来代替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映射对象。

+0

你一定对于任何给定字典“深度”,其中的一个关键'@ ref'存在,关键'@ id'不?这样你就不会覆盖一个给定的键值对时“改变”,他们'@ ref'键 - 值对以'@ id'。 – dfri

+0

@dfri我110%确定“@id”键存在广告是唯一的 – Jigen

回答

1

我认为查找替换方法效率不高,因为您必须对数据执行多次传递(直到找不到任何@ref字符串)。

您应该充分利用您的JSON模型引用类型语义(与值类型相反)并解析它,将解析对象中的@ref保留为出错引用。每一个对象,你解析你应该可以通过@id引用缓存添加。然后在第二遍中,您将通过缓存重新连接每个引用,以使用刚刚构建的查找表作为查找表。

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

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 } 
    } 
} 

(一个人这个假设人可以有{"id": "xx", "name": "xx", "other": {"@ref": "xx"}},其中“其他”是other是可选

这是一个普遍的做法,而不是特定的实现,但它会根据您的需要是非常特定领域。

更新有一个类似的协议叫做JSON API(IMO误导名称,但它利用由ID引用JSON对象的相同的方法)。这里是斯威夫特的实现:https://github.com/wvteijlingen/spine它可能是值得检查出来

+0

@我正在使用[ObjectMapper](https://github.com/Hearst-DD/ObjectMapper)为此目的,但我需要使用类似的东西来替代json对象 – Jigen

+0

,正如我前面提到的那样,我不会用JSON替换原始对象的方法,因为它会产生次优性能,您可能会在对象之间引用循环引用,这会导致您通过JSON并重新开始。如果ObjectMapper不符合您的需求,请考虑替换或扩展ObjectMapper –