如何在 Swift 中解码具有许多唯一键的嵌套 JSON?

Posted

技术标签:

【中文标题】如何在 Swift 中解码具有许多唯一键的嵌套 JSON?【英文标题】:How to decode a nested JSON with many unique keys in Swift? 【发布时间】:2018-04-30 02:52:01 【问题描述】:

我的问题是我可以用来解码具有许多不同键的 JSON 的最佳方法是什么?现在,我正在为每一个创建一个 var。这似乎是低效/硬编码,我有大约 8 个这样的不同菜单要解码。

这是我的 JSON:(很长,我知道)


  "Brunch": 
    "BEAR FIT": [
      "Savory Tofu, Spinach, Tomato Scramble"
    ], 
    "BEAR FUSION": [
      "Roasted Red & Gold Beets", 
      "Baked Ham", 
      "Parslied Potatoes", 
      "Roasted Zuchhini Squash Medley", 
      "Vegan Celebration Roast", 
      "Steamed Rice", 
      "Brown Rice"
    ], 
    "BEAR NECESSITIES": [
      "Rolled Oatmeal", 
      "Italian Wedding Soup"
    ], 
    "BEAR SWEETS": [
      "Blueberry Muffin", 
      "Cranberry Orange Scone", 
      "Assorted Danish"
    ], 
    "BREAKFAST PLATE": [
      "Hashbrown Tri Patty", 
      "Spiced French Toast", 
      "Breakfast Veggie Patty"
    ], 
    "GOLDEN GRILL": [
      "Waffle Bar Toppings"
    ], 
    "ITALIAN CORNER": [
      "Omelet Bar"
    ], 
    "PASTAS": [
      "Breadsticks", 
      "Pasta", 
      "Whole Wheat Pasta", 
      "Creamy Alfredo Sauce", 
      "Beef Bolognese Sauce"
    ], 
    "SMOOTHIES": [
      "Peach Smoothie"
    ], 
    "SPECIALTY SALADS": [
      "Macaroni Salad"
    ]
  , 
  "Dinner": 
    "BEAR FIT": [
      "Vegetable Caribbean Blend", 
      "Three Bean Chili", 
      "Brown Rice"
    ], 
    "BEAR FUSION": [
      "Chicken Vindaloo", 
      "Chana Masala", 
      "Brown Rice", 
      "Steamed Rice"
    ], 
    "BEAR NECESSITIES": [
      "Garden Vegetable Soup with Tomato", 
      "Italian Wedding Soup"
    ], 
    "BEAR SWEETS": [
      "Raspberry Sammie", 
      "Chocolate Chunk Brownie", 
      "Pumpkin Pie"
    ], 
    "CAL-ZONE": [
      "Mushroom & Olive Flatbread", 
      "Meat Lovers Pizza", 
      "Pepperoni Pizza"
    ], 
    "GOLDEN GRILL": [
      "Fish Sandwich", 
      "Malibu Burger", 
      "Shoestring Fries"
    ], 
    "PASTAS": [
      "Breadsticks", 
      "Pasta", 
      "Whole Wheat Pasta", 
      "Creamy Alfredo Sauce", 
      "Beef Bolognese Sauce"
    ], 
    "SPECIALTY SALADS": [
      "Macaroni Salad"
    ], 
    "THE BIG C": [
      "Hawaiian BBQ Pork", 
      "Blackened Tilapia with Lemon Pepper", 
      "Teriyaki Tofu", 
      "Steamed Rice", 
      "Suateed Cabbage", 
      "Cinnamon Glazed Carrot"
    ]
  

这是我现在拥有的解析器:

struct WeekendMenu: Decodable 
    struct Brunch: Decodable 
        var BEAR_FIT: [String]
        var BEAR_FUSION: [String]
        var BEAR_NECESSITIES: [String]
        var BEAR_SWEETS: [String]
        var BREAKFAST_PLATE: [String]
        var GOLDEN_GRILL: [String]
        var ITALIAN_CORNER: [String]
        var PASTAS: [String]
        var SMOOTHIES: [String]
        var SPECIALTY_SALADS: [String]
        private enum CodingKeys: String, CodingKey 
            case BEAR_FIT  = "BEAR FIT"
            case BEAR_FUSION  = "BEAR FUSION"
            case BEAR_NECESSITIES  = "BEAR NECESSITIES"
            case BEAR_SWEETS  = "BEAR SWEETS"
            case BREAKFAST_PLATE  = "BREAKFAST PLATE"
            case GOLDEN_GRILL  = "GOLDEN GRILL"
            case ITALIAN_CORNER  = "ITALIAN CORNER"
            case PASTAS  = "PASTAS"
            case SMOOTHIES  = "SMOOTHIES"
            case SPECIALTY_SALADS  = "SPECIALTY SALADS"
        
    
    struct Dinner: Decodable 
        //TODO
    
    var brunch: String
    var dinner: String
    private enum CodingKeys: String, CodingKey 
        case brunch = "Brunch"
        case dinner = "Dinner"
    

【问题讨论】:

通常创建结构来检查传入的 JSON 是否符合所需的结构。您也可以使用字典来解码其中的 JSON 并获取所需键的值,就像过去一样 【参考方案1】:

在这种情况下,我建议将 JSON 解码为字典 [String:[String]]

struct WeekendMenu: Decodable 
    private enum CodingKeys : String, CodingKey  case brunch = "Brunch", dinner = "Dinner" 

    let brunch: [String:[String]]
    let dinner: [String:[String]]

枚举字典,对键进行排序以获得相同的顺序

let result = try JSONDecoder().decode(WeekendMenu.self, from: data)
for key in result.brunch.keys.sorted() 
    print(key, result.brunch[key]!)

for key in result.dinner.keys.sorted() 
    print(key, result.dinner[key]!)


或者编写一个自定义初始化程序将字典解码为自定义结构Category,键变为name,值变为dishes数组。

struct WeekendMenu: Decodable 
    private enum CodingKeys : String, CodingKey  case brunch = "Brunch", dinner = "Dinner" 

    let brunch: [Category]
    let dinner: [Category]

     init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let brunch = try container.decode([String:[String]].self, forKey: .brunch)
        let brunchKeys = brunch.keys.sorted()
        self.brunch = brunchKeys.map  Category(name: $0, dishes: brunch[$0]!) 
        let dinner = try container.decode([String:[String]].self, forKey: .dinner)
        let dinnerKeys = dinner.keys.sorted()
        self.dinner = dinnerKeys.map  Category(name: $0, dishes: dinner[$0]!) 
    


struct Category 
    let name : String
    let dishes : [String]

【讨论】:

以上是关于如何在 Swift 中解码具有许多唯一键的嵌套 JSON?的主要内容,如果未能解决你的问题,请参考以下文章

带有可配置键的 Swift 4 JSON 解码

当您不知道 Swift 中的项目类型时,如何解码嵌套的 JSON 数据? [复制]

使用 JSONDecoder Swift 解码具有整数值的字符串键 [关闭]

使用 jq 将嵌套的 JSON 文件分解为具有唯一键的平面列表

如何使用 Codable 解码具有更改键的 json 响应?

ObjectMapper 和具有唯一键的数组