Разбор json внутри другой json строки в swift4 - PullRequest
0 голосов
/ 03 февраля 2020

Я пытаюсь разобрать json. Но проблема в том, что у меня есть json внутри него другая json строка. Как:

{
    "count": 284,
    "next": "http://X:X:X:X:8080/api/sensor/last5feed?page=2&search=XXXXX",
    "previous": null,
    "results": [
        {
            "id": 571,
            "feed": "{'app_id': 'XXXXX', 'dev_id': 'XXXX', 'hardware_serial': 'XXXXX', 'port': 6, 'counter': 4290, 'payload_raw': 'AQEBIwXsF4IAAAA=', 'payload_fields': {'aamsg_type': 'weather', 'abstatus': 0, 'batteryV': 3.5, 'battery_low': 'no', 'humiP': 60.2, 'tempC': 15.2}, 'metadata': {'time': '2020-01-23T15:09:32.350967362Z', 'frequency': 868.1, 'modulation': 'LORA', 'data_rate': 'SF7BW125', 'airtime': 61696000, 'coding_rate': '4/5', 'gateways': [{'gtw_id': 'XXXXX', 'timestamp': 3227230963, 'time': '2020-01-23T15:09:32.326146Z', 'channel': 0, 'rssi': -98, 'snr': 4.8, 'rf_chain': 1, 'latitude': 57.124737, 'longitude': -2.1646452, 'altitude': 90, 'location_source': 'registry'}]}}",
            "created_at": "2020-01-23T15:09:32.630326Z",
            "sensor": 1
        },
        {
            "id": 569,
            "feed": "{'app_id': 'XXXXXX', 'dev_id': 'XXXX', 'hardware_serial': 'XXXX', 'port': 6, 'counter': 4289, 'payload_raw': 'XXXXX', 'payload_fields': {'aamsg_type': 'weather', 'abstatus': 0, 'batteryV': 3.5, 'battery_low': 'no', 'humiP': 57.6, 'tempC': 16.9}, 'metadata': {'time': '2020-01-23T14:09:32.132070865Z', 'frequency': 867.3, 'modulation': 'LORA', 'data_rate': 'SF7BW125', 'airtime': 61696000, 'coding_rate': '4/5', 'gateways': [{'gtw_id': 'XXXXXX', 'timestamp': 3921981659, 'time': '2020-01-23T14:09:32.104672Z', 'channel': 4, 'rssi': -107, 'snr': 8.2, 'rf_chain': 0, 'latitude': 57.124737, 'longitude': -2.1646452, 'altitude': 90, 'location_source': 'registry'}]}}",
            "created_at": "2020-01-23T14:09:32.448929Z",
            "sensor": 1
        }
}

Я получаю значения до подачи. Но я не могу разобрать дальше, мой код:

if(status_code == 200){
  if let json = response.data {
    do{
      let data = try JSON(data: json)
      let result = data["results"].arrayObject! as NSArray
      let ct = result.count
       if(ct != 0 ) {
       self.noDataFound.isHidden = true
       for i in 0...ct-1 {
          let data = result[i] as? NSDictionary
          let feed = data?.value(forKey: "feed") as? NSString
          let data3 = try JSON(data: feed as! Data) . 
          print(data3)
        }
    }
} catch {} }}

Мне нужно получить hardware_serial из канала. Может ли любое тело, пожалуйста, помогите мне, что я делаю здесь неправильно! Спасибо !!!

Ответы [ 3 ]

1 голос
/ 03 февраля 2020
  1. Неверная строка для ключа feed JSON. Вы должны заменить одинарные кавычки на двойные.
  2. Создать Data объект из строки (приведение типа не работает).
  3. Создать JSON объект из data.
  4. Получите нужные значения.

Примечание:

Не используйте NS... типов сбора и NSString в Swift.

0 голосов
/ 03 февраля 2020

Сначала снимите кусок, который вы хотите:

struct ResultWrapper: Decodable {
    let results: [Result]
}

А затем создайте пользовательский декодер для извлечения подачи, которое искажено. Одиночные кавычки недопустимы JSON. В качестве хака следующий код просто заменяет все одинарные кавычки на двойные, но это не сработает, если есть встроенные кавычки-одинарные кавычки.

struct Result: Decodable {
    enum CodingKeys: String, CodingKey { case feed }
    let feed: Feed
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        // inner JSON is mal-formed. Have to fix it.
        let feedString = try container.decode(String.self, forKey: .feed)
            .replacingOccurrences(of: "'", with: "\"")

        feed = try JSONDecoder().decode(Feed.self, from: Data(feedString.utf8))
    }
}

Наконец, декодирование Feed является механическим , но требует пользовательских CodingKeys. Я рекомендую quicktype для этого:

// https://app.quicktype.io?share=7O6iNJ3ugXb4mr84TIoG
struct Feed: Codable {
    var appID, devID, hardwareSerial: String
    var port, counter: Int
    var payloadRaw: String
    var payloadFields: PayloadFields
    var metadata: Metadata

    enum CodingKeys: String, CodingKey {
        case appID = "app_id"
        case devID = "dev_id"
        case hardwareSerial = "hardware_serial"
        case port, counter
        case payloadRaw = "payload_raw"
        case payloadFields = "payload_fields"
        case metadata
    }
}

// MARK: - Metadata
struct Metadata: Codable {
    var time: String
    var frequency: Double
    var modulation, dataRate: String
    var airtime: Int
    var codingRate: String
    var gateways: [Gateway]

    enum CodingKeys: String, CodingKey {
        case time, frequency, modulation
        case dataRate = "data_rate"
        case airtime
        case codingRate = "coding_rate"
        case gateways
    }
}

// MARK: - Gateway
struct Gateway: Codable {
    var gtwID: String
    var timestamp: Int
    var time: String
    var channel, rssi: Int
    var snr: Double
    var rfChain: Int
    var latitude, longitude: Double
    var altitude: Int
    var locationSource: String

    enum CodingKeys: String, CodingKey {
        case gtwID = "gtw_id"
        case timestamp, time, channel, rssi, snr
        case rfChain = "rf_chain"
        case latitude, longitude, altitude
        case locationSource = "location_source"
    }
}

// MARK: - PayloadFields
struct PayloadFields: Codable {
    var aamsgType: String
    var abstatus: Int
    var batteryV: Double
    var batteryLow: String
    var humiP, tempC: Double

    enum CodingKeys: String, CodingKey {
        case aamsgType = "aamsg_type"
        case abstatus, batteryV
        case batteryLow = "battery_low"
        case humiP, tempC
    }
}
0 голосов
/ 03 февраля 2020

Используйте Codable для анализа вышеуказанного ответа JSON.

Модели:

struct Root: Codable {
    let count: Int
    let next: String
    let previous: String?
    let results: [Result]
}

struct Result: Codable {
    let id: Int
    let feed, createdAt: String
    let sensor: Int
}

Анализ JSON data вроде так,

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let response = try decoder.decode(Root.self, from: data)
    print(response)
} catch {
    print(error)
}
...