2016-07-04 92 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 –