如何使用Swift的Decodable来解析您只知道或关心几个字段的任意JSON字符串? [英] How can one use Swift's Decodable to parse an arbitrary JSON string where you only know or care about a few fields?

查看:67
本文介绍了如何使用Swift的Decodable来解析您只知道或关心几个字段的任意JSON字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The new Swift "Decoder" class sounds like a great way to parse JSON data, but all of the examples I've found use a well-known, well-defined 'struct' to do so.

在我的情况下,我正在查询一个返回巨大JSON字符串的任意网站,我只关心一些(深度嵌套的)字段,所以我不想全部那个时候定义一个'结构'来实现它们。

In my case I'm querying an arbitrary website that returns a HUGE JSON string and I only care about a few of the (deeply nested) fields, so I don't want to take all that time to define a 'struct' to get at them.

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

Is it even possible to do this with "Decoder"? And if so, how does one go about it?

推荐答案

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

The question seems to be based on a misapprehension about how Decodable works. As a convenience, Decodable is willing to do some automatic code generation behind the scenes so that you can define a struct or nest of structs and just decode the entirety of the JSON. But you are not required to take advantage of that in order to decode JSON.


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

  • There is no need to define struct properties for "fields" you don't care about. If a JSON dictionary contains 100 keys and your corresponding struct contains just one property, no problem; that key will be fetched, and no others.

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

With regard to the "deeply nested" part, it should not take you much time to write simple nested structs that perform the dive to reach the dictionary you really care about. But if you don't want to do even that, you could write an implementation of init(from:) that dives down and fetches out the desired values.

换句话说,如果您认为Decodable是主要的<$ c $实现c> init(from:),并学会编写它需要的代码,你会看到这个JSON可以用几个简单的简单代码行解析。

In other words, if you think of Decodable as consisting primarily of your implementation of init(from:), and learn to write the code that it needs, you will see that this JSON can be parsed in a few quick simple lines of code.

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

As an example, here's a JSON sketch of a deeply nested piece of information with a bunch of extra information at every level that we want to ignore:

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

我想做的是定义一个非常简单的struct只包含深刻的结构嵌套 name

What I'd like to do is define a very simple struct Person that consists solely of the deeply nested name:

struct Person : Decodable {
    let name : String
}

我能做到!为此,我自己实现了Decodable,提供了一个hooverCodingKey采用者结构和 init(来自:)的实现,就像这样(这可能看起来像很多工作,但事实并非如此,因为AnyCodingKey实现是样板,从这里,以及 init(编码器:) 实现只是几行易于编写的代码):

I can do that! To do so, I implement Decodable myself, supplying a "hoover" CodingKey adopter struct and an implementation of init(from:), like this (this may look like a lot of work, but it isn't, because the AnyCodingKey implementation is boilerplate, copied and pasted from here, and the init(coder:) implementation is just a few lines of code that were easy to write):

    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并获取名称信息时,这是微不足道的:

When I want to dive into the JSON and grab the name information, it's trivial:

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

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

The result is a Person object with name value "matt". Note that I didn't have to add any of the ignore keys and I didn't need to make a nest of structs.

这篇关于如何使用Swift的Decodable来解析您只知道或关心几个字段的任意JSON字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆