3

我正在使用 iOS Mapbox SDK从来自 3rd 方 APIMGLShapeCollectionFeature的 goejson数据创建一个。FeatureCollection

guard let feature = try? MGLShape(data: jsonData, encoding: String.Encoding.utf8.rawValue) as? MGLShapeCollectionFeature else {
    print("Could not cast to specified MGLShapeCollectionFeature")
    return
}

问题是 API 有时会返回一个无效的 geojson,其中单个Feature不包含有效坐标(见下文),并使用正确MGLShape的 a 初始化失败。'NSInvalidArgumentException', reason: 'A multipoint must have at least one vertex.'

有没有办法在手动解析和修复geojson的过程中过滤掉并删除那些无效Features的?FeatureCollection

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "icaoId": "KBOS",
        "airSigmetType": "AIRMET",
        "hazard": "IFR"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [

          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "icaoId": "KSLC",
        "airSigmetType": "AIRMET",
        "hazard": "IFR"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -106.63,
              49.06
            ],
            [
              -104.12,
              48.95
            ],
            [
              -104.17,
              44.8
            ],
            [
              -106.91,
              46.38
            ],
            [
              -106.63,
              49.06
            ]
          ]
        ]
      }
    }
  ]
}
4

2 回答 2

4

一种可能的解决方案是将 JSON 解码Codable为结构,过滤空项并将对象编码回:

struct FeatureCollection : Codable {
    let type : String
    var features : [Feature]
}

struct Feature : Codable {
    let type : String
    let properties : Properties
    let geometry : Geometry
}

struct Properties : Codable {
    let icaoId, airSigmetType, hazard : String
}

struct Geometry : Codable {
    let type : String
    let coordinates : [[[Double]]]
}

do {
    var result = try JSONDecoder().decode(FeatureCollection.self, from: jsonData)
    let filteredFeatures = result.features.filter{$0.geometry.coordinates != [[]]}
    result.features = filteredFeatures
    let filteredData = try JSONEncoder().encode(result)
    guard let feature = try? MGLShape(data: filteredData, encoding: String.Encoding.utf8.rawValue) as? MGLShapeCollectionFeature else {
        print("Could not cast to specified MGLShapeCollectionFeature")
        return
    }
} catch {
    print(error)
}
于 2019-02-17T11:42:19.457 回答
1

正如您所建议的,我自己进行了过滤并在Data

extension Data {

    func removeEmptyCoordinates() throws -> Data {
        guard var geojson = try JSONSerialization.jsonObject(with: self, options: []) as? [String: Any] else {
            return self
        }
        fix(geojson: &geojson,
            processFeatureIf: NSPredicate(format: "geometry.type == 'Polygon'"),
            keepFeatureIf: NSPredicate(format: "%K[0][SIZE] >= 2", "geometry.coordinates"))
        return try JSONSerialization.data(withJSONObject: geojson, options: [])
    }

    private func fix(geojson: inout [String: Any], processFeatureIf: NSPredicate, keepFeatureIf: NSPredicate) {
        guard let type = geojson["type"] as? String, type == "FeatureCollection" else {
            // "Not a FeatureCollection"
            return
        }
        // "No features to fix"
        guard let features = geojson["features"] as? [[String: Any]] else { return }

        let filtered = features.filter { feature in
            if !processFeatureIf.evaluate(with: feature) {
                // not processing
                return true
            }
            return keepFeatureIf.evaluate(with: feature)
        }
        geojson["features"] = filtered
    }
}
于 2019-02-17T11:44:24.440 回答