如何在ReasonML中解码GeoJson?

时间:2019-12-22 06:32:46

标签: json geojson reason bucklescript bs-json

请评论一下如何在ReasonML中解码GeoJson文件?我尝试在解码器中解码没有“字段纬度和经度”的坐标,但找不到任何信息来解析JSON文件中的字段坐标。

GeoJson文件

 "features": [
     {
       "type": "Feature",
       "geometry": {
         "type": "Point",
         "coordinates": [
           131.469670264,
           33.3158712032
         ]
       },
       "properties": {
         "index": 0,
         "alias": "海地獄-別府市",
         "name": "Umi-Jigoku",
         "image_url": "https://s3-media1.fl.yelpcdn.com/bphoto/7T1aXG9Q3CAtEbwqFm3Nlw/o.jpg"
       }

ReasonML中的JsonDecoder(bs-json)

[@genType]
type properties = {
  index: int,
  alias: string,
  name: string,
  image_url: string,
  geometry: coordinates,
}
and coordinates = {
  latitude: float,
  longitude: float,
};

let places = "../json/alljapan.json";

module Decode = {
  let coordinates = json =>
    Json.Decode.{
      latitude: json |> field("latitude", float),
      longitude: json |> field("longitude", float),
    };

  let properties = json =>
    Json.Decode.{
      index: json |> field("index", int),
      alias: json |> field("alias", string),
      name: json |> field("name", string),
      image_url: json |> field("image_url", string),
      geometry: json |> field("geometry", coordinates),
    };
};

let line = places |> Json.parseOrRaise |> Decode.line;

2 个答案:

答案 0 :(得分:2)

在工作中,我们编写了一个名为GeoReason的库,其目的是为GeoJSON数据结构提供Reason类型,构造函数,编码器和解码器(以及一些辅助功能,例如eq)。 RFC-7946 spec

我还没有尝试过将库与React Native一起使用,但是我认为它应该可以在任何可以将Reason编译为JS的地方使用。

概述

  • GeoJSON为很多“或”(特征或几何,其中几何是点或线或...)关系建模,很容易表示为“原因”变体
  • GeoJSON紧凑,更喜欢数组(作为元组),这很难读取。为此,我们使用原因记录。
  • 我们使用bs-decode解码值
  • “功能”带有额外的元数据(“属性”字段),该元数据可以是带有元数据的任何JSON对象...我们不会尝试通过键=> json字典对此进行解码:Js.Dict.t(Js.Json.t)

用法

假设您具有类型Js.Json.t的JSON值,并且已按照README中的说明安装了GeoReason,则可以像这样解码和使用数据:

// this is a `Belt.Result` that is either `Ok` with the GeoJSON data, or
// Error with information describing what went wrong while decoding
let decoded = GeoJSON.decode(myFileData);

switch (decoded) {
| Error(parseError) =>
  Decode.ParseError.failureToDebugString(parseError) |> Js.log;

// if the GeoJSON value is a "Feature", it may have the following fields,
// but note that technically all of them are optional according to the spec.
// if you want to decode the dictionary of properties, you can do so here
| Ok(GeoJSON.Feature({id, geometry, properties})) =>
  properties
  ->Belt.Option.flatMap(dict => Js.Dict.get(dict, "image_url"))
  ->Belt.Option.flatMap(json => Js.Json.decodeString(json))
  ->Belt.Option.map(url => /* do something with the url? */);

| Ok(Geometry(Point({latlong, altitude})) =>
  /* use latitude and longitude? */

| Ok(Geometry(Polygon(data))) => /* ... */

| Ok(_) =>
  // lots more cases to handle, like line geometries,
  // geometry collections, feature collections, etc...
};

如您所见,对GeoJSON值可能进行的所有匹配都是一个相当复杂的过程,因此它在某种程度上取决于您希望如何使用这些值。我在库中添加了一些帮助程序,例如GeoJSON.getPolygons,它将尝试获取任何GeoJSON值的多边形列表(如果没有多边形,则返回一个空列表)。如果您发现其他有用的帮手,请随时提出问题。

答案 1 :(得分:1)

您可能应该使用@ mlms13建议的GeoReason,但是如果您仍然想使用bs-json对其进行解码,则可以利用元组在BuckleScript中作为数组实现并使用pair的事实。解码器以获取值,然后map将该值转换为您的记录类型:

let coordinates = json =>
  Json.Decode.(
    pair(float, float)
    |> map(((latitude, longitude)) => {latitude, longitude})
  );