如何将 NOAA 天气 JSON 解码为 Swift 结构

问题描述 投票:0回答:1

当我从 api.weather.gov 请求数据时,我得到以下 JSON(摘录,仅限第一个时段或小时:

{
"@context": [
"https://geojson.org/geojson-ld/geojson-context.jsonld",
{
"@version": "1.1",
"wx": "https://api.weather.gov/ontology#",
"geo": "http://www.opengis.net/ont/geosparql#",
"unit": "http://codes.wmo.int/common/unit/",
"@vocab": "https://api.weather.gov/ontology#"
}
],
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-95.406033800000003,
39.349170399999998
],
[
-95.40841660000001,
39.326447799999997
],
[
-95.382835100000008,
39.324328799999996
],
[
-95.380447500000002,
39.347050999999997
],
[
-95.406033800000003,
39.349170399999998
]
]
]
},
"properties": {
"units": "us",
"forecastGenerator": "HourlyForecastGenerator",
"generatedAt": "2024-07-07T13:28:43+00:00",
"updateTime": "2024-07-07T10:55:15+00:00",
"validTimes": "2024-07-07T04:00:00+00:00/P7DT21H",
"elevation": {
"unitCode": "wmoUnit:m",
"value": 9.1440000000000001
},
"periods": [
{
"number": 1,
"name": "",
"startTime": "2024-07-07T09:00:00-04:00",
"endTime": "2024-07-07T10:00:00-04:00",
"isDaytime": true,
"temperature": 82,
"temperatureUnit": "F",
"temperatureTrend": "",
"probabilityOfPrecipitation": {
"unitCode": "wmoUnit:percent",
"value": 15
},
"dewpoint": {
"unitCode": "wmoUnit:degC",
"value": 26.111111111111111
},
"relativeHumidity": {
"unitCode": "wmoUnit:percent",
"value": 89
},
"windSpeed": "5 mph",
"windDirection": "ESE",
"icon": "/icons/land/day/tsra_hi,20?size=small",
"shortForecast": "Isolated Showers And Thunderstorms",
"detailedForecast": ""
},
{
"number": 2,

除了第一个元素之外,我已经能够将其大部分映射到 JSON 结构:

"@context": [
"https://geojson.org/geojson-ld/geojson-context.jsonld",
{
"@version": "1.1",
"wx": "https://api.weather.gov/ontology#",
"geo": "http://www.opengis.net/ont/geosparql#",
"unit": "http://codes.wmo.int/common/unit/",
"@vocab": "https://api.weather.gov/ontology#"
}
],

在我看来,这就像一个 Swift 字典 [String: [VersionStruct]],但在 JSON 中看起来像一个数组,第一个元素是字符串,第二个元素是字符串结构,我如何将其表示为 Swift 结构,我很困惑,谢谢

json swift struct weather noaa
1个回答
0
投票

如果

@context
属性始终包含两个元素的列表,第一个元素是字符串,第二个元素可由给定类型表示,则可以使用元组:

struct GeoJSON {
  let context: (String, Context)
  ...

  struct Context {
    let version, wx, geo, unit, vocab: String
  }
}

元组不是

Decodable
,因此您需要提供自定义
Decodable
实现:

struct GeoJSON: Decodable {
  let context: (String, Context)

  enum CodingKeys: String, CodingKey {
    case context = "@context"
  }

  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    var nested = try container.nestedUnkeyedContainer(forKey: .context)
    let string = try nested.decode(String.self)
    let context = try nested.decode(GeoJSON.Context.self)
    self.context = (string, context)
  }
}

extension GeoJSON {
  struct Context: Codable {
    let version, wx, geo, unit, vocab: String

    enum CodingKeys: String, CodingKey {
      case wx, geo, unit, version = "@version", vocab = "@vocab"
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.