Expand description
§Introduction
This crate helps you read and write GeoJSON — a format for encoding geographic data structures.
To get started, add geojson to your Cargo.toml.
cargo add geojson§Types and crate structure
This crate is structured around the GeoJSON spec (IETF RFC 7946),
and users are encouraged to familiarise themselves with it. The elements specified in this spec
have corresponding struct and type definitions in this crate, e.g. FeatureCollection, Feature,
etc.
There are two primary ways to use this crate.
The first, most general, approach is to write your code to deal in terms of these structs from the GeoJSON spec. This allows you to access the full expressive power of GeoJSON with the speed and safety of Rust.
Alternatively, and commonly, if you only need geometry and properties (and not, e.g.
foreign members), you can bring your own
types, and use this crate’s serde integration to serialize and deserialize your custom
types directly to and from a GeoJSON Feature Collection. See more on using your own types with
serde.
If you want to use GeoJSON as input to or output from a geometry processing crate like
geo, see the section on using geojson with
geo-types.
§Using structs from the GeoJSON spec
A GeoJSON object can be one of three top-level objects, reflected in this crate as the
GeoJson enum members of the same name.
- A
Geometryrepresents points, curves, and surfaces in coordinate space. - A
Featureusually contains aGeometryand some associated data, for example a “name” field or any other properties you’d like associated with theGeometry. - A
FeatureCollectionis a list ofFeatures.
Because Feature and FeatureCollection are more flexible, bare Geometry GeoJSON
documents are rarely encountered in the wild. As such, conversions from Geometry
or Geometry Value to Feature objects are provided via the From trait.
Beware: A common point of confusion arises when converting a GeoJson
GeometryCollection. Do you want it converted to a single
Feature whose geometry is a GeometryCollection, or do you
want a FeatureCollection with each element of the
GeometryCollection converted to its own Feature, potentially
with their own individual properties. Either is possible, but it’s important you understand
which one you want.
§Examples
§Reading
GeoJson can be deserialized by calling str::parse:
use geojson::{Feature, GeoJson, Geometry, Value};
use std::convert::TryFrom;
let geojson_str = r#"
{
"type": "Feature",
"properties": { "food": "donuts" },
"geometry": {
"type": "Point",
"coordinates": [ -118.2836, 34.0956 ]
}
}
"#;
let geojson: GeoJson = geojson_str.parse::<GeoJson>().unwrap();
let feature: Feature = Feature::try_from(geojson).unwrap();
// read property data
assert_eq!("donuts", feature.property("food").unwrap());
// read geometry data
let geometry: Geometry = feature.geometry.unwrap();
if let Value::Point(coords) = geometry.value {
assert_eq!(coords, vec![-118.2836, 34.0956]);
}
§Writing
GeoJson can be serialized by calling to_string:
use geojson::{Feature, GeoJson, Geometry, Value};
let geometry = Geometry::new(Value::Point(vec![-120.66029, 35.2812]));
let geojson = GeoJson::Feature(Feature {
bbox: None,
geometry: Some(geometry),
id: None,
// See the next section about Feature properties
properties: Some(get_properties()),
foreign_members: None,
});
let geojson_string = geojson.to_string();§Feature properties
The geojson crate is built on top of serde_json. Consequently,
some fields like feature.properties hold serde_json
values.
use geojson::{JsonObject, JsonValue};
let mut properties = JsonObject::new();
let key = "name".to_string();
properties.insert(key, JsonValue::from("Firestone Grill"));§Parsing
GeoJSON’s spec is quite simple, but it has several subtleties that must be taken into account when parsing it:
- The
geometryfield of aFeatureis anOption— it can be blank. GeometryCollections contain otherGeometryobjects, and can nest.- We strive to produce strictly valid output, but we are more permissive about what we accept as input.
Here’s a minimal example which will parse and process a GeoJSON string.
use geojson::{GeoJson, Geometry, Value};
/// Process top-level GeoJSON Object
fn process_geojson(gj: &GeoJson) {
match *gj {
GeoJson::FeatureCollection(ref ctn) => {
for feature in &ctn.features {
if let Some(ref geom) = feature.geometry {
process_geometry(geom)
}
}
}
GeoJson::Feature(ref feature) => {
if let Some(ref geom) = feature.geometry {
process_geometry(geom)
}
}
GeoJson::Geometry(ref geometry) => process_geometry(geometry),
}
}
/// Process GeoJSON geometries
fn process_geometry(geom: &Geometry) {
match geom.value {
Value::Polygon(_) => println!("Matched a Polygon"),
Value::MultiPolygon(_) => println!("Matched a MultiPolygon"),
Value::GeometryCollection(ref gc) => {
println!("Matched a GeometryCollection");
// !!! GeometryCollections contain other Geometry types, and can
// nest — we deal with this by recursively processing each geometry
for geometry in gc {
process_geometry(geometry)
}
}
// Point, LineString, and their Multi– counterparts
_ => println!("Matched some other geometry"),
}
}
fn main() {
let geojson_str = r#"
{
"type": "GeometryCollection",
"geometries": [
{"type": "Point", "coordinates": [0,1]},
{"type": "MultiPoint", "coordinates": [[-1,0],[1,0]]},
{"type": "LineString", "coordinates": [[-1,-1],[1,-1]]},
{"type": "MultiLineString", "coordinates": [
[[-2,-2],[2,-2]],
[[-3,-3],[3,-3]]
]},
{"type": "Polygon", "coordinates": [
[[-5,-5],[5,-5],[0,5],[-5,-5]],
[[-4,-4],[4,-4],[0,4],[-4,-4]]
]},
{ "type": "MultiPolygon", "coordinates": [[
[[-7,-7],[7,-7],[0,7],[-7,-7]],
[[-6,-6],[6,-6],[0,6],[-6,-6]]
],[
[[-9,-9],[9,-9],[0,9],[-9,-9]],
[[-8,-8],[8,-8],[0,8],[-8,-8]]]
]},
{"type": "GeometryCollection", "geometries": [
{"type": "Polygon", "coordinates": [
[[-5.5,-5.5],[5,-5],[0,5],[-5,-5]],
[[-4,-4],[4,-4],[0,4],[-4.5,-4.5]]
]}
]}
]
}
"#;
let geojson = geojson_str.parse::<GeoJson>().unwrap();
process_geojson(&geojson);
}§Use geojson with other crates by converting to geo-types
geo-types are a common geometry format used across many
geospatial processing crates. The geo-types feature is enabled by default.
§Convert geo-types to geojson
From is implemented on the Value enum variants to allow conversion from geo-types
Geometries.
// requires enabling the `geo-types` feature
let geo_point: geo_types::Point<f64> = geo_types::Point::new(2., 9.);
let geo_geometry: geo_types::Geometry<f64> = geo_types::Geometry::from(geo_point);
assert_eq!(
geojson::Value::from(&geo_point),
geojson::Value::Point(vec![2., 9.]),
);
assert_eq!(
geojson::Value::from(&geo_geometry),
geojson::Value::Point(vec![2., 9.]),
);If you wish to produce a FeatureCollection from a homogeneous collection of geo-types, a
From impl is provided for geo_types::GeometryCollection:
// requires enabling the `geo-types` feature
use geojson::FeatureCollection;
use geo_types::{polygon, point, Geometry, GeometryCollection};
use std::iter::FromIterator;
let poly: Geometry<f64> = polygon![
(x: -111., y: 45.),
(x: -111., y: 41.),
(x: -104., y: 41.),
(x: -104., y: 45.),
].into();
let point: Geometry<f64> = point!(x: 1.0, y: 2.0).into();
let geometry_collection = GeometryCollection::from_iter(vec![poly, point]);
let feature_collection = FeatureCollection::from(&geometry_collection);
assert_eq!(2, feature_collection.features.len());§Convert geojson to geo-types
The geo-types feature implements the TryFrom trait,
providing fallible conversions to geo-types Geometries
from GeoJson, Value, Feature, FeatureCollection or Geometry types.
§Convert geojson to geo_types::Geometry<f64>
// This example requires the `geo-types` feature
use geo_types::Geometry;
use geojson::GeoJson;
use std::convert::TryFrom;
use std::str::FromStr;
let geojson_str = r#"
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
-0.13583511114120483,
51.5218870403801
]
}
}
"#;
let geojson = GeoJson::from_str(geojson_str).unwrap();
// Turn the GeoJSON string into a geo_types Geometry
let geom = geo_types::Geometry::<f64>::try_from(geojson).unwrap();§Caveats
- Round-tripping with intermediate processing using the
geotypes may not produce identical output, as e.g. outerPolygonrings are automatically closed. geojsonattempts to output valid geometries. In particular, it may re-orientPolygonrings when serialising.
The geojson_example and
polylabel_cmd crates contain example
implementations which may be useful if you wish to perform this kind of processing yourself and require
more granular control over performance and / or memory allocation.
§Using your own types with serde
If your use case is simple enough, you can read and write GeoJSON directly to and from your own types using serde.
Specifically, the requirements are:
- Your type has a
geometryfield.- If your
geometryfield is ageo-typesGeometry, you must use the providedserialize_with/deserialize_withhelpers. - Otherwise, your
geometryfield must be acrate::Geometry.
- If your
- Other than
geometry, you may only use a Feature’sproperties- all other fields, like foreign members, will be lost.
#[derive(serde::Serialize, serde::Deserialize)]
struct MyStruct {
// Serialize as geojson, rather than using the type's default serialization
#[serde(serialize_with = "serialize_geometry", deserialize_with = "deserialize_geometry")]
geometry: geo_types::Point<f64>,
name: String,
count: u64,
}See more in the serialization and deserialization modules.
Re-exports§
Modules§
- de
- Build your struct from GeoJSON using
serde - errors
- Module for all GeoJSON-related errors
- feature
- ser
- Write your struct to GeoJSON using
serde
Structs§
- Feature
- Feature Objects
- Feature
Collection - Feature Collection Objects
- Feature
Reader - Enumerates individual Features from a GeoJSON FeatureCollection
- Feature
Writer - Write Features to a FeatureCollection
- Geometry
- Geometry Objects
Enums§
Functions§
- quick_
collection Deprecated - A shortcut for producing
geo_typesGeometryCollection objects from arbitrary valid GeoJSON input.
Type Aliases§
- Bbox
- Bounding Boxes
- Json
Object - Json
Value - Line
String Type - Point
Type - Polygon
Type - Position
- Positions