Как декодировать GeoJson в ReasonML?

Прокомментируйте, пожалуйста, как декодировать файл GeoJson в ReasonML? Я пытаюсь расшифровать координаты без "широты и долготы поля" в декодере, но я не могу найти никакой информации о том, как анализировать координаты поля в файле 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"
       }

JsonDecoder (bs-json) в ReasonML

[@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 ответа

Вам, вероятно, следует использовать GeoReason, как предлагает @mlms13, но если вы все еще хотите декодировать его самостоятельно, используя bs-json вы можете использовать тот факт, что кортежи реализованы как массивы в BuckleScript, и использовать pair декодер для получения значений, затем map это к вашему типу записи:

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

На работе мы написали библиотеку под названием GeoReason с целью предоставления типов Reason, конструкторов, кодировщиков и декодеров (вместе с некоторыми вспомогательными функциями, такими какeq) для структур данных GeoJSON в соответствии со спецификацией RFC-7946.

Я не пробовал использовать библиотеку с React Native, но полагаю, что она должна работать везде, где вы можете скомпилировать Reason в JS.

Обзор

  • GeoJSON моделирует множество отношений "или" (элемент или геометрия, где геометрия - это точка, линия или...), которые легко выразить как варианты причины.
  • GeoJSON компактен, предпочитает массивы (как кортежи), которые трудно читать. Для этого мы используем записи Reason.
  • Декодируем значения с помощью bs-decode
  • "Возможности" идут с дополнительными метаданными (поле "свойства"), которыми может быть любой объект JSON с метаданными... Мы не пытаемся декодировать это за пределами словаря key => json: Js.Dict.t(Js.Json.t)

Применение

Предполагая, что у вас есть значение JSON типа Js.Json.t, и вы установили GeoReason, следуя инструкциям в README, вы можете декодировать и использовать свои данные следующим образом:

// 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 (возвращая пустой список, если полигонов не было). Не стесняйтесь открывать вопросы, если есть дополнительные помощники, которые вам пригодятся.

Другие вопросы по тегам