【问题标题】:Swift 5 Parsing strange json formatSwift 5 解析奇怪的 json 格式
【发布时间】:2020-11-16 05:14:11
【问题描述】:

我正在尝试解析 JSON,但不断收到不正确的格式错误。我从 FoodData Central(美国农业部的营养 API)返回的 JSON 如下:

{
    dataType = "Survey (FNDDS)";
    description = "Chicken thigh, NS as to cooking method, skin not eaten";
    fdcId = 782172;
    foodNutrients =     (
                {
            amount = "24.09";
            id = 9141826;
            nutrient =             {
                id = 1003;
                name = Protein;
                number = 203;
                rank = 600;
                unitName = g;
            };
            type = FoodNutrient;
        },
                {
            amount = "10.74";
            id = "9141827";
            nutrient =             {
                id = 1004;
                name = "Total lipid (fat)";
                number = 204;
                rank = 800;
                unitName = g;
            };
            type = FoodNutrient;
        }
    );
}

我的结构:

struct Root: Decodable {
     let description: String
     let foodNutrients: FoodNutrients
}

struct FoodNutrients: Decodable {
     // What should go here???
}

从 JSON 来看,foodNutrients 看起来是一个未命名对象的数组,每个对象的值都有 amount: String、id: String 和 nutrient: Nutrient(有 id、name 等...)但是,忘记了Nutrient 对象,我什至无法解析数量。

struct FoodNutrients: Decodable {
     let amounts: [String]
}

我不认为它是一个字符串数组,但我不知道 foodNutrients 中的 () 表示什么。

我将如何解析这个 JSON。我正在使用 Swift 5 和 JSONDecoder。为了得到 JSON,我使用 JSONSerializer,然后打印出上面的 JSON。

【问题讨论】:

  • 它不是格式良好的 json。我检查了一个 json 格式化程序和验证程序。无效 (RFC 8259)
  • 我也检查过,这很奇怪,因为它来自美国农业部的 API。我所做的就是使用 JSONSerialization 将数据转换为 JSON,然后打印它

标签: json swift parsing swift5 jsondecoder


【解决方案1】:

不是 JSON。这是openStep 格式的属性列表。

这就是它的建模方式(使用String 而不是Int):

struct Root: Decodable {
    let description: String
    let foodNutrients: [FoodNutrient]
}

struct FoodNutrient: Decodable {
    let id: String
    let amount: String
    let nutrient: Nutrient
}

struct Nutrient: Decodable {
    let name: String
    let number: String
    let rank: String
    let unitName: String
}

然后像这样解码:

try PropertyListDecoder().decode(Root.self, from: yourStr)

【讨论】:

  • 我收到此错误:无法读取数据,因为它的格式不正确。
  • @Nobadi 您是否要解码您发布的确切数据?并且不要打印error.localizedDescription - 这是没有意义的。将错误转换为DecodingError
  • 否定的。我只展示一块,因为来自 RESTApi 的整个响应是巨大的。但是,我将整个回复粘贴到了谷歌文档中:docs.google.com/document/d/…
  • 以及将其转换为 DecodingError 后我该怎么办?
  • @Nobadi 打印出来。调试。检查它是哪种类型的 DecodingError。我已经向您展示了如何从您的问题中解码示例。您现在应该可以完成剩下的工作了。
【解决方案2】:

foodNutrients 中的 () 表示它包含一个对象数组 - 在这种情况下是 FoodNutrient 对象。因此,您的根对象应如下所示:

struct Root: Decodable {
    let description: String
    let foodNutrients: [FoodNutrient]
}

现在foodNutrient除了营养对象直接了:

struct FoodNutrient: Decodable {
    let id: Int // <-- in your example it is an integer and in the second object a string, choose the fitting one from the API
    let amount: String
    let nutrient: Nutrient
}

营养对象应该是这样的:

struct Nutrient: Decodable {
    let name: String
    let number: Int
    let rank: Int
    let unitName: String 
}

使用Decodable 是序列化 JSON 的一种好方法。希望有帮助。快乐编码:)

【讨论】:

  • 我得到同样的错误:无法读取数据,因为它的格式不正确。
  • 这个解决方案是正确的。唯一的问题是数量变量注册为 Double 而不是 String
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-15
  • 1970-01-01
  • 2012-01-09
  • 1970-01-01
相关资源
最近更新 更多