如何使用Swift的Decodable来解析您只知道或关心几个字段的任意JSON字符串?

新的Swift“Decoder”类听起来像是解析JSON数据的好方法,但我发现的所有示例都使用了一个众所周知的,定义良好的“struct”来实现。

在我的情况下,我正在查询一个返回一个巨大的JSON字符串的任意网站,我只关心一些(深度嵌套的)字段,所以我不想花费所有时间来定义一个’struct’来获取在他们身上

用“解码器”甚至可以做到这一点吗? 如果是这样,那怎么办呢?

这个问题似乎是基于对Decodable如何工作的误解。 为方便起见,Decodable愿意在幕后进行一些自动代码生成,以便您可以定义结构的结构或嵌套,并只解码整个JSON。 但是您不需要利用它来解码JSON。

  • 无需为您不关心的“字段”定义结构属性。 如果JSON字典包含100个键,并且您的相应结构只包含一个属性,则没有问题; 该密钥将被提取,而没有其他密钥。

  • 关于“深度嵌套”部分,它不应该花费你太多时间来编写简单的嵌套结构来执行潜水以达到你真正关心的字典。 但是如果你不想这样做,你可以写一个init(from:)的实现,它会向下潜并取出所需的值。

换句话说,如果您认为Decodable 主要由您的init(from:)实现组成,并且学会编写它需要的代码,您将会看到这个JSON可以通过一些简单的简单代码行进行解析。

作为一个例子,这里是一个深度嵌套信息的JSON草图,其中包含我们想要忽略的每个级别的一堆额外信息:

 { "ignore": true, "outer1": { "ignore": true, "outer2": { "ignore": true, "outer3": { "name": "matt", "ignore": true } } } } 

我想要做的是定义一个非常简单的struct Person,它只包含深层嵌套的name

 struct Person : Decodable { let name : String } 

我能做到! 为此,我自己实现了Decodable,提供了一个“hoover”CodingKey采用者结构和init(from:) ,就像这样(这可能看起来像很多工作,但事实并非如此,因为AnyCodingKey实现是样板文件,从这里复制和粘贴, init(coder:)实现只是几行易于编写的代码):

  struct Person : Decodable { let name : String struct AnyCodingKey : CodingKey { var stringValue: String var intValue: Int? init(_ codingKey: CodingKey) { self.stringValue = codingKey.stringValue self.intValue = codingKey.intValue } init(stringValue: String) { self.stringValue = stringValue self.intValue = nil } init(intValue: Int) { self.stringValue = String(intValue) self.intValue = intValue } } init(from decoder: Decoder) throws { var con = try! decoder.container(keyedBy: AnyCodingKey.self) con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer1")) con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer2")) con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer3")) let name = try! con.decode(String.self, forKey: AnyCodingKey(stringValue:"name")) self.name = name } } 

当我想深入了解JSON并获取name信息时,它是微不足道的:

 let person = try! JSONDecoder().decode(Person.self, from: json) 

结果是name "matt"的Person对象。 请注意,我没有添加任何ignore键,我不需要创建一个结构嵌套。

当然你可以实现这个但是同时使用JSonSerializationDecodable ,你必须序列化json直到达到所需内容然后解码它,但我建议创建根键的结构只有然后解码,想想它,因为它是从顶部的路径到底部不会解码不在所需内容路径中的密钥