Home > OS >  swift can not make struct for parsing geoJSON
swift can not make struct for parsing geoJSON

Time:10-14

I have geoJSON file:

{
  "type": "Feature",
  "geometry": {
    "type": "MultiPolygon",
    "coordinates": [
      [
        [
          [
            40.303141,
            55.9765684
          ],
          [
            40.3033449,
            55.9765114
          ],
          [
            40.3034017,
            55.976575
          ],
          [
            40.3031979,
            55.9766321
          ],
          [
            40.303141,
            55.9765684
          ]
        ]
      ]
    ]
  },
  "properties": {
    "@id": 4305947573,
    "building": "yes"
  }
}

I'm interested in properties:

"properties":{"@id":4305947573,"building":"yes"}

I want parse "properties", and make structure:

struct Feature: Decodable {
let type: String
let properties: Dictionary<String, String> }

It's work good, but then i add parameter in geoJSON: "@id":4305947573

4305947573 - this is Int variable, and parser don't parse geoJSON.

I think i need modify my struct Feature. I want to parser understand and String, and Int in properties.

Help me please. Thank you

CodePudding user response:

You can use a custom CodingKey with a custom object.

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

The object will look something like

struct Feature: Codable{
    var type: String
    var geometry: Geometry
    var properties: Property
    struct Geometry: Codable{
        var type: String
        var coordinates: [[[[Double]]]]
    }
    struct Property: Codable{
        var id: Int
        var building: String
        
        enum CodingKeys: String, CodingKey{
            case id = "@id"
            case building
        }
    }
}

Then you can decode with a simple decoder or any other parser.

func decode(string: String) throws -> Feature?{
    let decoder = JSONDecoder()
    return try decoder.decode(Feature.self, from: string.data(using: .utf8)!)
}

CodePudding user response:

There are a number of GeoJSON swift libraries (search github) that you could use instead of re-inventing the wheel.

If you really want to code it yourself, try this approach, where the dynamic keys and values of properties are decoded into a dictionary of var data: [String: Any], as shown.

Use the struct models like this:

let result = try JSONDecoder().decode(Feature.self, from: data)

Models

struct Feature: Decodable {
    let type: String
    var properties: Properties
    // ...
}

struct Properties: Decodable {
    var data: [String: Any] = [:]

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DynamicKey.self)
        container.allKeys.forEach { key in
            if let theString = try? container.decode(String.self, forKey: key) {
                self.data[key.stringValue] = theString
            }
            if let theInt = try? container.decode(Int.self, forKey: key) {
                self.data[key.stringValue] = theInt
            }
        }
    }
}

struct DynamicKey: CodingKey {
    var intValue: Int?
    init?(intValue: Int) {
        self.intValue = intValue
        self.stringValue = ""
    }
    
    var stringValue: String
    init?(stringValue: String) {
        self.stringValue = stringValue
        self.intValue = nil
    }
}
  • Related