Parse complex json code

2019-09-21 19:36发布

问题:

I have the following JSON code and want to parse it in Swift. I use Alamofire to get the JSON and have created a struct for the parsing:

    {  
   "-8802586561990153106-1804221538-5":{  
      "zug":{  
         "klasse":"RB",
         "nummer":"28721"
      },
      "ankunft":{  
         "zeitGeplant":"1804221603",
         "zeitAktuell":"1804221603",
         "routeGeplant":[  
            "Wiesbaden Hbf",
            "Mainz Hbf"
         ]
      },
      "abfahrt":{  
         "zeitGeplant":"1804221604",
         "zeitAktuell":"1804221604",
         "routeGeplant":[  
            "Gro\u00df Gerau",
            "Klein Gerau",
            "Weiterstadt"
         ]
      }
   },
   "8464567322535526441-1804221546-15":{  
      "zug":{  
         "klasse":"RB",
         "nummer":"28724"
      },
      "ankunft":{  
         "zeitGeplant":"1804221657",
         "zeitAktuell":"1804221708",
         "routeGeplant":[  
            "Aschaffenburg Hbf",
            "Mainaschaff"
         ]
      },
      "abfahrt":{  
         "zeitGeplant":"1804221658",
         "zeitAktuell":"1804221709",
         "routeGeplant":[  
            "Mainz-Bischofsheim"
         ]
      }
   }
}

I have created a struct for this that looks like this:

struct CallResponse: Codable {
    struct DirectionTrain: Codable {
        struct Train: Codable {
            let trainClass: String
            let trainNumber: String
        }
        struct Arrival: Codable {
            let line: String
            let eta: Date
            let ata: Date
            let platform: String
            let route: [String]
        }
        struct Departure: Codable {
            let line: String
            let etd: Date
            let atd: Date
            let platform: String
            let route: [String]
        }
    }
 }

The rest of my code is:

 Alamofire.request(url!).responseJSON { response in
            switch response.result {
            case .success:
                let decoder = JSONDecoder()
                let parsedResult = try! decoder.decode(CallResponse.self, from: response.data!)
            case .failure(let error):
                print(error)
            }
        }

When I run this code the error message is:

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "train", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"train\", intValue: nil) (\"train\").", underlyingError: nil))

Can anyone help me find my problem? Thank you for your answers!

回答1:

The problem is merely that your structs look nothing at all like your JSON!

Your JSON is a dictionary whose keys have names like "-8802586561990153106-1804221538-5" and "8464567322535526441-1804221546-15". But I don't see you declaring any struct that deals with those keys.

Then each of those turns out to be a dictionary with keys like "zug", "ankunft", and "abfahrt". But I don't see you declaring any struct that deals with those keys either.

And then the "zug" has keys "klasse" and "nummer"; you don't have those either.

And so on.

Either your structs must look exactly like your JSON, or else you must define CodingKeys and possibly also implement init(from:) to deal with any differences between your structs and your JSON. I suspect that the keys "-8802586561990153106-1804221538-5" and "8464567322535526441-1804221546-15" are unpredictable, so you will probably have to write init(from:) in order to deal with them.

For example, I was able to decode your JSON like this (I do not really recommend using try!, but we decoded without error and it's just a test):

    struct Entry : Codable {
        let zug : Zug
        let ankunft : AnkunftAbfahrt
        let abfahrt : AnkunftAbfahrt
    }
    struct Zug : Codable {
        let klasse : String
        let nummer : String
    }
    struct AnkunftAbfahrt : Codable {
        let zeitGeplant : String
        let zeitAktuell : String
        let routeGeplant : [String]
    }
    struct Top : Decodable {
        var entries = [String:Entry]()
        init(from decoder: Decoder) throws {
            struct CK : CodingKey {
                var stringValue: String
                init?(stringValue: String) {
                    self.stringValue = stringValue
                }
                var intValue: Int?
                init?(intValue: Int) {
                    return nil
                }
            }
            let con = try! decoder.container(keyedBy: CK.self)
            for key in con.allKeys {
                self.entries[key.stringValue] = 
                    try! con.decode(Entry.self, forKey: key)
            }
        }
    }
    // d is a Data containing your JSON
    let result = try! JSONDecoder().decode(Top.self, from: d)


标签: swift swift4