geojson

repository·main·Indexed 43 days ago

https://github.com/georust/geojson

A Rust crate for reading and writing GeoJSON (RFC 7946) vector geographic data. It provides tools for high-level manipulation of GeoJSON objects such as Features, Geometries, and FeatureCollections, with support for serialization and deserialization via serde. Version 1.0.0 requires a minimum Rust version of 1.34.

Tokens
8K
Snippets
29
Records
33
Agent score
54%

What's inside geojson

  1. Use the GeoJson enum to handle any valid GeoJSON object

    main

    The GeoJson enum is the primary entry point for working with GeoJSON in this crate. It acts as a container that can represent any valid GeoJSON object: a Geometry, a Feature, or a FeatureCollection. This is particularly useful when you are parsing data and do not know the specific type of GeoJSON object beforehand.

    Use GeoJson::from_str or GeoJson::from_reader to parse JSON strings or streams into this enum, then use pattern matching to access the underlying data.

    use geojson::{GeoJson, Feature, FeatureCollection, Geometry};
    
    // When you're not sure what you're getting, use `GeoJson`.
    let geojson_str = r#"{
        "type": "Feature",
        "geometry": {
            "type": "Point",
            "coordinates": [102.0, 0.5]
        },
        "properties": null
    }"#;
    
    let geojson: GeoJson = geojson_str.parse().unwrap();
    match geojson {
        GeoJson::Geometry(geometry) => println!("geometry: {:?}", geometry),
        GeoJson::Feature(feature) => println!("feature: {:?}", feature),
        GeoJson::FeatureCollection(feature_collection) => {
            println!("feature_collection: {:?}", feature_collection)
        }
    }
  2. Understand GeometryValue and Geometry

    main

    The library distinguishes between GeometryValue and Geometry:

    1. GeometryValue: An enum representing the core GeoJSON geometry type and its specific coordinate structure (e.g., Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection). It is the payload of a geometry.
    2. Geometry: A wrapper struct that follows the GeoJSON specification for a Geometry Object. It contains:
      • value: The GeometryValue (the type and coordinates).
      • bbox: An optional bounding box (Option<Bbox>).
      • foreign_members: An optional map of extra fields (Option<JsonObject>) allowed by the GeoJSON spec.

    When creating geometries, it is recommended to use the Geometry::new_* constructors which wrap a GeometryValue into a Geometry struct.

  3. How GeoJSON objects are structured

    main

    The crate is structured around the GeoJSON spec (RFC 7946). A GeoJSON document is represented by the GeoJson enum, which can contain one of three top-level objects:

    1. Geometry: Represents points, lines, and surfaces in coordinate space.
    2. Feature: Contains a Geometry and associated data (properties).
    3. FeatureCollection: A list of Features.

    Because Feature and FeatureCollection are more flexible, bare Geometry documents are less common. Conversions from Geometry or GeometryValue to Feature objects are provided via the From trait.

    use geojson::{GeoJson, Feature, FeatureCollection, Geometry};
  4. Handle Foreign Members in GeoJSON

    main

    GeoJSON allows for 'foreign members'—extra JSON fields not defined in the spec. This crate captures them in the foreign_members field on Geometry, Feature, and FeatureCollection structs.

    Limitation: Foreign member keys must not collide with reserved GeoJSON fields (coordinates, geometries, id, geometry, properties, features), or they will be consumed by the reserved field parser instead.

    use geojson::{GeoJson, Feature};
    
    let geojson_str = r#"{ "type": "Feature", "geometry": {"type": "Point", "coordinates": [0.0, 0.0]}, "properties": null, "title": "my point" }"#;
    
    let feature = geojson_str.parse::<GeoJson>().unwrap();
    if let GeoJson::Feature(feature) = feature {
        let foreign_members = feature.foreign_members.unwrap();
        assert_eq!(foreign_members["title"], "my point");
    }
  5. Use your own types with serde

    main

    You can deserialize GeoJSON directly into your own custom structs using serde. To do this correctly:

    1. Your struct must have a geometry field.
    2. If the field is a geo-types geometry, use the geojson::ser::serialize_geometry and geojson::de::deserialize_geometry helpers.
    3. Otherwise, the field must be a crate::Geometry.

    Note: Using this method means any fields other than geometry and properties (like foreign_members) will be lost during deserialization.

    #[derive(Serialize, Deserialize)]
    struct MyStruct {
        #[serde(serialize_with = "geojson::ser::serialize_geometry", deserialize_with = "geojson::de::deserialize_geometry")]
        geometry: geo_types::Point<f64>,
        name: String,
        count: u64,
    }
  6. Convert between geojson and geo-types

    main

    If the geo-types feature is enabled, you can convert between geojson types and geo-types geometries.

    Convert geo-types to geojson (Lossless)

    Use the From trait to convert geo-types geometries into geojson::Geometry or geojson::GeometryValue.

    Convert geojson to geo-types (Fallible)

    Use the TryFrom trait to convert GeoJson, GeometryValue, Feature, FeatureCollection, or Geometry into geo_types::Geometry<f64>. This is a fallible operation.

    Caveats:

    • Round-tripping through geo-types might not produce identical output (e.g., outer Polygon rings are automatically closed).
    • geojson may re-orient Polygon rings during serialization to ensure valid geometries.
    // Convert geojson to geo_types::Geometry<f64>
    #[cfg(feature = "geo-types")]
    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": [1.0, 2.0]
     }
    }"#;
    let geojson = GeoJson::from_str(geojson_str).unwrap();
    let geom = Geometry::<f64>::try_from(geojson).unwrap();
  7. Parse GeoJSON strings into GeoJson objects

    main

    You can parse a GeoJSON string into a GeoJson enum using the .parse::<GeoJson>() method. This allows you to convert raw string data into structured Rust types representing GeoJSON features, geometries, or collections.

    use geojson::GeoJson;
    
    let geojson_str = r"#
    {
        "type": "Feature",
        "properties": {
            "name": "Firestone Grill"
        },
        "geometry": {
            "type": "Point",
            "coordinates": [-120.66029,35.2812]
        }
    }
    "#;
    
    let geojson = geojson_str.parse::<GeoJson>().unwrap();
  8. Serialize GeoJSON objects to strings

    main

    To write GeoJSON, construct the appropriate types such as Geometry, JsonObject, and Feature, then wrap them in the GeoJson enum. You can then use the .to_string() method to serialize the object into a GeoJSON-formatted string.

    use geojson::{Feature, GeoJson, Geometry, JsonObject, JsonValue};
    
    let geometry = Geometry::new_point([-120.66029, 35.2812]);
    
    let mut properties = JsonObject::new();
    properties.insert(
        String::from("name"),
        JsonValue::from("Firestone Grill"),
    );
    
    let geojson = GeoJson::Feature(Feature {
        bbox: None,
        geometry: Some(geometry),
        id: None,
        properties: Some(properties),
        foreign_members: None,
    });
    
    let geojson_string = geojson.to_string();
  9. Read GeoJSON from a string

    main

    You can deserialize a GeoJSON string into a Feature (or other GeoJSON types) by using the str::parse method. This is powered by serde integration.

    use geojson::{Feature, GeoJson, Geometry, GeometryValue};
    use std::convert::TryFrom;
    
    let geojson_str = r"#
    {
      "type": "Feature",
      "properties": { "food": "donuts" },
      "geometry": {
        "type": "Point",
        "coordinates": [ -118.2836, 34.0956 ]
      }
    }
    "#;
    
    let feature: Feature = geojson_str.parse().unwrap();
    
    // read property data
    assert_eq!("donuts", feature.property("food").unwrap());
    
    // read geometry data
    let geometry: Geometry = feature.geometry.unwrap();
    if let GeometryValue::Point { coordinates } = geometry.value {
        assert_eq!(coordinates.as_slice(), &[-118.2836, 34.0956]);
    }
  10. Write GeoJSON to a string

    main

    You can serialize GeoJSON objects to a string by calling .to_string(). For Feature objects, you can define properties using JsonObject and JsonValue (which are wrappers around serde_json types).

    use geojson::{Feature, GeoJson, Geometry, JsonObject, JsonValue};
    
    fn get_properties() -> JsonObject {
        let mut properties = JsonObject::new();
        properties.insert(
            String::from("name"),
            JsonValue::from("Firestone Grill"),
        );
        properties
    }
    
    fn main() {
        let geometry = Geometry::new_point([-120.66029, 35.2812]);
    
        let feature = Feature {
            bbox: None,
            geometry: Some(geometry),
            id: None,
            properties: Some(get_properties()),
            foreign_members: None,
        };
    
        let geojson_string = feature.to_string();
    }