当前位置: 首页 > 面试题库 >

如何解码具有不同类型的JSON属性?

张博涛
2023-03-14
问题内容

我有一个JSON

{
"tvShow": {
    "id": 5348,
    "name": "Supernatural",
    "permalink": "supernatural",
    "url": "http://www.episodate.com/tv-show/supernatural",
    "description": "Supernatural is an American fantasy horror television series created by Eric Kripke. It was first broadcast on September 13, 2005, on The WB and subsequently became part of successor The CW's lineup. Starring Jared Padalecki as Sam Winchester and Jensen Ackles as Dean Winchester, the series follows the two brothers as they hunt demons, ghosts, monsters, and other supernatural beings in the world. The series is produced by Warner Bros. Television, in association with Wonderland Sound and Vision. Along with Kripke, executive producers have been McG, Robert Singer, Phil Sgriccia, Sera Gamble, Jeremy Carver, John Shiban, Ben Edlund and Adam Glass. Former executive producer and director Kim Manners died of lung cancer during production of the fourth season.<br>The series is filmed in Vancouver, British Columbia and surrounding areas and was in development for nearly ten years, as creator Kripke spent several years unsuccessfully pitching it. The pilot was viewed by an estimated 5.69 million viewers, and the ratings of the first four episodes prompted The WB to pick up the series for a full season. Originally, Kripke planned the series for three seasons but later expanded it to five. The fifth season concluded the series' main storyline, and Kripke departed the series as showrunner. The series has continued on for several more seasons with Sera Gamble and Jeremy Carver assuming the role of showrunner.",
    "description_source": "http://en.wikipedia.org/wiki/Supernatural_(U.S._TV_series)#Spin-off_series",
    "start_date": "2005-09-13",
    "end_date": null,
    "country": "US",
    "status": "Running",
    "runtime": 60,
    "network": "The CW",
    "youtube_link": "6ZlnmAWL59I",
    "image_path": "https://static.episodate.com/images/tv-show/full/5348.jpg",
    "image_thumbnail_path": "https://static.episodate.com/images/tv-show/thumbnail/5348.jpg",
    "rating": "9.6747",
    "rating_count": "249",
    "countdown": null
}
}

rating不同系列中的值是Int(“ rating”:0)或String(“ rating”:“ 9.6747”)。

我正在使用Codable / Decodable协议解析JSON:

struct DetailModel : Decodable {

var id : Int?
var name : String?
var permalink : String?
var url : String?
var description : String
var description_source : String?
var start_date : String?
var end_date : String?
var country : String?
var status : String?
var runtime : Int?
var network : String?
var youtube_link : String?
var image_path : String?
var image_thumbnail_path : String?
var rating: String
var rating_count : String?
var countdown : String?
var genres : [String]?
var pictures : [String]?
var episodes : [EpisodesModel]?
}

如果rating == String,则我的代码有效,并且我具有JSON中的所有变量,但是如果rating ==
Int,则全部为nil。我应该怎么做来解析所有类型变量rating一次IntString

我的可解码功能:

    func searchSerialDetail(id: Int, completion: @escaping (DetailModel?) -> Void){

    let parameters: [String: Any] = ["q": id]

    Alamofire.request(DetailNetworkLayer.url, method: .get, parameters: parameters).response { (jsonResponse) in

        if let jsonValue =  jsonResponse.data {
            let jsonDecoder = JSONDecoder()
                let detail = try? jsonDecoder.decode(DetailModel.self, from: jsonValue)
                completion(detail)
        }
    }
}

谢谢。


问题答案:

您将必须实现自己的协议,func encode(to encoder: Encoder) throws并且init(from decoder: Decoder) throws这都是Codable协议的属性。然后将rating变量更改为 枚举

看起来像这样:

enum Rating: Codable {
    case int(Int)
    case string(String)

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .int(let v): try container.encode(v)
        case .string(let v): try container.encode(v)
        }
    }

    init(from decoder: Decoder) throws {
        let value = try decoder.singleValueContainer()

        if let v = try? value.decode(Int.self) {
            self = .int(v)
            return
        } else if let v = try? value.decode(String.self) {
            self = .string(v)
            return
        }

        throw Rating.ParseError.notRecognizedType(value)
    }

    enum ParseError: Error {
        case notRecognizedType(Any)
    }
}

然后,您DetailModel只需更改rating: Stringrating: Rating

这有效,我已经用这些JSON字符串进行了测试。

// int rating
{   
    "rating": 200,
    "bro": "Success"
}

// string rating
{
    "rating": "200",
    "bro": "Success"
}

编辑 :我发现了一种更好的实现方法init(from decoder: Decoder) throws,它产生了更好的错误消息,通过使用此方法,您现在可以省略ParseError枚举。

init(from decoder: Decoder) throws {
    let value = try decoder.singleValueContainer()
    do {
        self = .int(try value.decode(Int.self))
    } catch DecodingError.typeMismatch {
        self = .string(try value.decode(String.self))
    }
}


 类似资料:
  • 问题内容: 例如: 因为json数组被解码为go数组,并且go数组需要显式定义类型,所以我不知道如何处理它。 问题答案: 首先,json无效,对象必须具有键,因此它应该类似于或just 。 而当您处理多种随机类型时,只需使用即可。

  • 问题内容: 如何使用Gson解析此JSON?我有一个具有多个对象类型的数组,但我不知道需要创建哪种对象来保存此结构。我无法更改json消息(我无法控制服务器)。 唯一起作用的类是 JSON消息 (请注意具有多个对象类型的数组。) 问题答案: 《 Gson用户指南》明确涵盖了以下内容: https://sites.google.com/site/gson/gson-user-guide#TOC-Se

  • 问题内容: 我目前正在使用Gson用Java编写RSS feed解析器。我正在将RSS的XML转换为JSON,然后使用Gson将JSON反序列化为Java POJO(有点回旋,但是有原因)。就下面列出的Feed#1( BBC )进行反序列化而言,一切工作正常,但是对于下面列出的Feed#2( NPR ),我开始抛出异常。 我认为我已经确定了问题,但不确定如何解决该问题: 这是由于以下两个RSS F

  • 我的代码中有以下对象。 如何最好地删除所有“地址”字段?因此,我得出以下结果。我一直在努力寻找这个基本问题的答案。

  • 我有一些json数据,看起来像 解析器被“无法构造值的实例(不存在创建者,如默认构造)”所阻塞:没有双精度/双参数构造函数/工厂方法从数字值反序列化(1.572553780732E9)” 我的数据类看起来像:

  • 问题内容: 假设我的数据类型包含一个属性,该属性可以在客户对象中包含任何JSON字典 该属性可以是任何任意的JSON映射对象。 在我可以使用反序列化的JSON(但使用新的Swift 4 协议)转换属性之前,我仍然想不出一种方法。 有谁知道如何在Swift 4中使用Decodable协议实现这一目标? 问题答案: 从我发现的要点中得到一些启发,我为和编写了一些扩展名。您可以在此处找到我的要旨的链接。