1

请评论如何在 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;
4

2 回答 2

2

在工作中,我们编写了一个名为GeoReason的库,其目标是为 GeoJSON 数据结构提供原因类型、构造函数、编码器和解码器(以及一些辅助函数,例如eq),遵循RFC-7946 规范

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

概述

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

用法

假设你有一个 type 的 JSON 值Js.Json.t,并且你已经按照 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 值的多边形列表(如果没有多边形,则返回一个空列表)。如果有其他对您有用的助手,请随意打开问题。

于 2019-12-22T18:22:33.913 回答
2

正如@mlms13 所建议的那样,您可能应该使用 GeoReason,但是如果您仍然想自己解码它,bs-json您可以利用元组在 BuckleScript 中作为数组实现的事实并使用pair解码器获取值,然后map将其添加到您的记录类型:

let coordinates = json =>
  Json.Decode.(
    pair(float, float)
    |> map(((latitude, longitude)) => {latitude, longitude})
  );
于 2019-12-22T20:53:33.347 回答