Swift, Как анализировать / декодировать JSON с помощью Decodable и Codable, когда ключ неизвестен / динамический

Ниже мой JSON, и я не могу декодировать (используя CodingKeys) Данные в ключе регионы представляют собой Словарь («IN-WB», «IN-DL» и т.д.), поскольку ключи являются динамическими, их можно более или менее изменять.

Пожалуйста, помогите мне разобрать то же самое с помощью Decodable и Codable.

Все данные должны быть в одной модели.

{
            "provider_code": "AIIN",
            "name": "Jio India",
            "regions": [
                {
                    "IN-WB": "West Bengal"
                },
                {
                    "IN-DL": "Delhi NCR"
                },
                {
                    "IN-TN": "Tamil Nadu"
                },
                {
                    "IN": "India"
                }
            ]
        }

Вы отвечаете за JSON? Учтите, что массив словарей, содержащий только одну пару ключ-значение соответственно, является очень неэффективной моделью. Лучше отправьте словарь, например { "code" : "IN-WB", "name" : "West Bengal"}, это, кстати, решает вашу проблему.

vadian 27.09.2018 09:49

Что вы имеете в виду под «Все данные должны быть в одной модели». ?)

Dmytro Shvetsov 27.09.2018 11:09
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
0
2
482
2

Ответы 2

Просто используйте Словарь для регионов.

struct Locations: Codable {
    let providerCode: String
    let name: String
    let regions: [[String: String]]

    enum CodingKeys: String, CodingKey {
        case providerCode = "provider_code"
        case name, regions
    }
}

Вы не можете создать конкретную модель для регионов, так как не знаете названия свойств.

Но вы можете создать регион (идентификатор, имя). Почему бы и нет, с помощью decoder.unkeyedContainer () или динамического ключа.

Dmytro Shvetsov 27.09.2018 11:31

вы не знаете ключ JSON? поэтому JSONDecoder не сможет этого сделать, вам нужно будет переопределить init(decoder:_) для анализа как [[String: String]], зациклить каждый найденный элемент и инициализировать регион, например Region(key, value)

Scriptable 27.09.2018 11:33

Один из возможных подходов, без словаря. Но сначала надо найти ключ)

Мне нравится этот стиль, так как мы можем использовать регионы с самого начала.

// example data.
let string = "{\"provider_code\":\"AIIN\",\"name\":\"Jio India\",\"regions\":[{\"IN-WB\":\"West Bengal\"},{\"IN-DL\":\"Delhi NCR\"},{\"IN-TN\":\"Tamil Nadu\"},{\"IN\":\"India\"}]}"
let data   = string.data(using: .utf8)!

// little helper
struct DynamicGlobalKey: CodingKey {
    var stringValue: String
    init?(stringValue: String) {
        self.stringValue = stringValue
    }

    var intValue: Int? { return nil }
    init?(intValue: Int) { return nil }
}

// model
struct Location: Decodable {
    let providerCode: String
    let name: String
    let regions: [Region]
}

extension Location {
    struct Region: Decodable {
        let key:  String
        let name: String

        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: DynamicGlobalKey.self)
            key  = container.allKeys.first!.stringValue
            name = try container.decode(String.self, forKey: container.allKeys.first!)
        }
    }
}

// example of decoding.
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

let location = try decoder.decode(Location.self, from: data)

Другие вопросы по теме