How to extract data from nested JSON with Swift 4 with dynamic keys

前端 未结 2 567
星月不相逢
星月不相逢 2021-01-06 12:09

I have a JSON data structure using unique keys that are created on upload. I can read all of it if I read each dictionary item line by line. However, I\'m trying to modify m

相关标签:
2条回答
  • 2021-01-06 12:43

    You can get keys from your current json as

     jq -r 'keys[]'
    

    After that query in the loop by each key retrieved

    0 讨论(0)
  • 2021-01-06 12:48

    You can try something like this:

    let data = jsonData.data(using: .utf8)
    let json = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
    let things = json["things"] as! [String:Any]
    
    for (thing_key, thing_value)   in things as [String:Any] {
    
        let thing = thing_value as! [String:Any]
        if let cases = thing["cases"] as? [String:Any]{
            for (case_key, case_value) in cases {
                print(case_key)
                print(case_value)
            }
        }
    }
    

    EDIT I initially missunderstood your question , here is your code improved to obtain the cases. It was a quick job so might not be optimal, but you get the idea:

    struct Thing: Decodable {
        let id: String
        let isActive: Bool
        let name: String
        let owner: String
        var cases: [Case]?
    
        init(id: String, isActive: Bool, name: String, owner: String , cases: [Case]?) {
            self.id = id
            self.isActive = isActive
            self.name = name
            self.owner = owner
            self.cases = cases
    
        }
    }
    struct User: Decodable {
        let id: String
        let name: String
    }
    struct Case: Decodable {
        let id: String
        let caseNumber: Int
    }
    struct ResponseData: Decodable {
        var things = [Thing]()
        var users = [User]()
    
    
        enum CodingKeys: String, CodingKey {
            case things
            case users
            case cases
        }
    
        private struct PhantomKeys: CodingKey {
            var intValue: Int?
            var stringValue: String
            init?(intValue: Int) { self.intValue = intValue; self.stringValue = "\(intValue)" }
            init?(stringValue: String) { self.stringValue = stringValue }
        }
    
        private enum ThingKeys: String, CodingKey {
            case isActive, name, owner, cases
        }
        private enum UserKeys: String, CodingKey {
            case name
        }
        private enum CaseKeys: String, CodingKey {
    
            case no
        }
    
        init(from decoder: Decoder) throws {
    
            let outer = try decoder.container(keyedBy: CodingKeys.self)
            let thingcontainer = try outer.nestedContainer(keyedBy: PhantomKeys.self, forKey: .things)
    
            for key in thingcontainer.allKeys {
                let aux = try thingcontainer.nestedContainer(keyedBy: ThingKeys.self, forKey: key)
    
                let name = try aux.decode(String.self, forKey: .name)
                let owner = try aux.decode(String.self, forKey: .owner)
                let isActive = try aux.decode(Bool.self, forKey: .isActive)
    
    
                var cases:[Case]? = []
                do{
                    let casescontainer = try aux.nestedContainer(keyedBy: PhantomKeys.self, forKey: .cases)
                        for case_key in casescontainer.allKeys{
    
                            let caseaux = try casescontainer.nestedContainer(keyedBy: CaseKeys.self, forKey: case_key)
                            let no = try caseaux.decode(Int.self, forKey: .no)
                            let thingCase = Case(id:case_key.stringValue, caseNumber: no)
                            cases?.append(thingCase)
                    }
    
                }catch{ }
    
    
                let thing = Thing(id: key.stringValue, isActive: isActive, name: name, owner: owner , cases: cases)
                things.append(thing)
            }
            let usercontainer = try outer.nestedContainer(keyedBy: PhantomKeys.self, forKey: .users)
    
            for key in usercontainer.allKeys {
                let aux = try usercontainer.nestedContainer(keyedBy: UserKeys.self, forKey: key)
                let name = try aux.decode(String.self, forKey: .name)
                let user = User(id: key.stringValue,name: name)
                users.append(user)
            }
        }
    }
    

    This produce this output:

    let data = json.data(using: .utf8)!
    let things = try JSONDecoder().decode(ResponseData.self, from: data).things
    print("-----")
    for thing in things{
        print(thing)
    }
    print("---")
    let users = try JSONDecoder().decode(ResponseData.self, from: data).users
    for user in users{
        print(user)
    }
    

    -----
    Thing(id: "456", isActive: true, name: "Bus", owner: "Joe", cases: Optional([]))
    Thing(id: "123", isActive: true, name: "Party", owner: "Bob", cases: Optional([__lldb_expr_283.Case(id: "case1", caseNumber: 1), __lldb_expr_283.Case(id: "case2", caseNumber: 2)]))
    ---
    User(id: "u1", name: "Summer")
    User(id: "u2", name: "Daffy")
    
    0 讨论(0)
提交回复
热议问题