简体   繁体   English

在swift4中的另一个json字符串中解析json

[英]Parse json inside another json string in swift4

I am trying to parse the json.我正在尝试解析 json。 But the problem is I have json inside to it another json String.但问题是我有一个 json 里面有另一个 json 字符串。 Like :喜欢 :

{
    "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
        }
}

I am getting the values till feed.我正在获取值直到饲料。 But I am not able to parse further, My code is :但我无法进一步解析,我的代码是:

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 {} }}

I need to get the hardware_serial from feed.我需要从提要中获取hardware_serial。 Can any body please help me what i am doing wrong here!!任何人都可以帮助我我在这里做错了什么!! Thanks!!!谢谢!!!

  1. The string for key feed is not valid JSON.密钥feed的字符串不是有效的 JSON。 You have to replace the single quotes with double quotes.您必须用双引号替换单引号。
  2. Create a Data object from the string (casting the type doesn't work).从字符串创建一个Data对象(转换类型不起作用)。
  3. Create a JSON object from the data.从数据创建一个 JSON 对象。
  4. Get the values you need.获取您需要的值。

Side note:边注:

Don't use NS... collection types and NSString in Swift.不要在 Swift 中使用NS...集合类型和NSString

Use Codable to parse the above JSON response.使用Codable解析上述 JSON 响应。

Models:楷模:

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
}

Parse the JSON data like so,像这样解析JSON data

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

First, peel off the piece you want:首先,剥下你想要的那一块:

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

And then build a custom decoder to extract feed, which is malformed.然后构建自定义解码器来提取格式错误的提要。 Single-quotes are not legal JSON.单引号不是合法的 JSON。 As a hack, the following code just substitutes all single-quotes with double-quotes, but this won't work if there are any embedded quoted-single-quotes.作为一个黑客,以下代码只是用双引号替换了所有单引号,但是如果有任何嵌入的带引号的单引号,这将不起作用。

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))
    }
}

Finally, decoding Feed is mechanical, but requires custom CodingKeys.最后,解码 Feed 是机械的,但需要自定义 CodingKeys。 I recommend quicktype for that:我推荐快速输入:

// 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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM