Minimal examples of GeoJSON parsing using Rust
OTHER License
These are three minimal examples demonstrating GeoJSON parsing using Rust. In order to run them, you'll need at least Stable Rust 1.34. In most cases, the easiest way to do this is using Rustup.
If you aren't familiar with it, it may be helpful to familiarise yourself with the GeoJSON spec, as this should make it obvious why e.g. Feature
geometries in rust-geojson
are Option
.
The example GeoJSON used is deliberately baroque: GeometryCollection
isn't in wide use, and the use of nested GeometryCollection
s is discouraged by the spec, being all but unknown "in the wild". Nevertheless, if we need to e.g. extract all Polygon
objects in an arbitrary GeoJSON file, we have to be able to process them – this turns out to be relatively painless using a recursive function.
The example code could be more minimal, but this is an ideal use case for Rayon in order to parallelise the processing, so iterators have been substituted for for { … }
loops to faciliate its use, leading to the requirement for Rust 1.21 or later. If you'd prefer to use for
loops and avoid iterators, the plain
branch is available.
Three different approaches to parsing GeoJSON are shown:
borrowed.rs
shows parsing using only borrowed data, and does not consume the GeoJSON, clone any part of it, or allocate – you're free to use geojson
again as soon as process_geojson
returns. Run it using cargo: cargo run --bin borrowed
owned.rs
shows parsing and conversion to Geo
types, which necessarily consumes the GeoJSON, as Geo
's primitives currently require owned data. To faciliate conversions of this kind,rust-geojson
provides the conversion::try_into
trait for this on its Value
structs. This approach is the most flexible, especially if you need to add or remove data, as opposed to modifying it. Run it using cargo: cargo run --bin owned
borrowed_modify.rs
(Run it using cargo: cargo run --bin borrowed_modify
) shows parsing and modification of geometries using only mutably borrowed data. The core idea can be seen in calculate_hull()
: ordinarily, take()
could be used to remove the T
from an Option<T>
– in this case a Geometry
– convert its value
to a Geo
type, and modify it before replacing it. However, this approach will only work for the Feature
type; input which contains top-level Geometry
and/or GeometryCollection
types can't be modified in this way, due to the lack of Option
. However, a more general approach involving std::mem::replace
, is possible:
&mut Geometry
(which all GeoJson
enum variants are guaranteed to have) on its value
, wrapping that in an Option
Geo
placeholder geometry is constructed, converted into a Value
, and swapped for the Value
we wish to modify, using replace
. The original geometry can then be modified or freely used, before being swapped back into the borrowed Geometry.value
, before the function returns.The polylabel_cmd
crate contains more advanced parsing and conversion code which has the same structure as these examples.