diff --git a/geozero/src/geojson/geojson_reader.rs b/geozero/src/geojson/geojson_reader.rs index e4eb695b..2b8a9175 100644 --- a/geozero/src/geojson/geojson_reader.rs +++ b/geozero/src/geojson/geojson_reader.rs @@ -58,11 +58,11 @@ pub fn read_geojson(mut reader: R, processor: &mut } pub fn read_geojson_fc(reader: R, processor: &mut P) -> Result<()> { - let mut idx = 0; - for feature in FeatureReader::from_reader(reader).features() { + processor.dataset_begin(None)?; + for (idx, feature) in FeatureReader::from_reader(reader).features().enumerate(){ process_geojson_feature(&feature?, idx, processor)?; - idx += 1; } + processor.dataset_end()?; Ok(()) } @@ -83,22 +83,15 @@ fn process_geojson(gj: &GeoGeoJson, processor: &mut P) -> R GeoGeoJson::FeatureCollection(ref collection) => { processor.dataset_begin(None)?; for (idx, feature) in collection.features.iter().enumerate() { - processor.feature_begin(idx as u64)?; - if let Some(ref properties) = feature.properties { - processor.properties_begin()?; - process_properties(properties, processor)?; - processor.properties_end()?; - } - if let Some(ref geometry) = feature.geometry { - processor.geometry_begin()?; - process_geojson_geom_n(geometry, idx, processor)?; - processor.geometry_end()?; - } - processor.feature_end(idx as u64)?; + process_geojson_feature(feature, idx, processor)? } processor.dataset_end()?; } - GeoGeoJson::Feature(ref feature) => process_geojson_feature(feature, 0, processor)?, + GeoGeoJson::Feature(ref feature) => { + processor.dataset_begin(None)?; + process_geojson_feature(feature, 0, processor)?; + processor.dataset_end()?; + } GeoGeoJson::Geometry(ref geometry) => { process_geojson_geom_n(geometry, 0, processor)?; } @@ -112,7 +105,6 @@ fn process_geojson_feature( idx: usize, processor: &mut P, ) -> Result<()> { - processor.dataset_begin(None)?; if feature.geometry.is_some() || feature.properties.is_some() { processor.feature_begin(idx as u64)?; if let Some(ref properties) = feature.properties { @@ -127,7 +119,6 @@ fn process_geojson_feature( } processor.feature_end(idx as u64)?; } - processor.dataset_end()?; Ok(()) } @@ -135,6 +126,7 @@ fn process_geojson_feature( fn process_geojson_geom(gj: &GeoGeoJson, processor: &mut P) -> Result<()> { match *gj { GeoGeoJson::FeatureCollection(ref collection) => { + processor.geometrycollection_begin(collection.features.len(), 0)?; for (idx, geometry) in collection .features .iter() @@ -144,6 +136,7 @@ fn process_geojson_geom(gj: &GeoGeoJson, processor: &mut P) -> { process_geojson_geom_n(geometry, idx, processor)?; } + processor.geometrycollection_end(0)?; } GeoGeoJson::Feature(ref feature) => { if let Some(ref geometry) = feature.geometry { @@ -367,7 +360,7 @@ mod test { let mut wkt_data: Vec = Vec::new(); assert!(read_geojson_fc(geojson.as_bytes(), &mut WktWriter::new(&mut wkt_data)).is_ok()); let wkt = std::str::from_utf8(&wkt_data).unwrap(); - assert_eq!(wkt, "MULTIPOLYGON(((173.020375 -40.919052,173.247234 -41.331999,173.958405 -40.926701,174.247587 -41.349155,174.248517 -41.770008,173.876447 -42.233184,173.22274 -42.970038,172.711246 -43.372288,173.080113 -43.853344,172.308584 -43.865694,171.452925 -44.242519,171.185138 -44.897104,170.616697 -45.908929,169.831422 -46.355775,169.332331 -46.641235,168.411354 -46.619945,167.763745 -46.290197,166.676886 -46.219917,166.509144 -45.852705,167.046424 -45.110941,168.303763 -44.123973,168.949409 -43.935819,169.667815 -43.555326,170.52492 -43.031688,171.12509 -42.512754,171.569714 -41.767424,171.948709 -41.514417,172.097227 -40.956104,172.79858 -40.493962,173.020375 -40.919052)),((174.612009 -36.156397,175.336616 -37.209098,175.357596 -36.526194,175.808887 -36.798942,175.95849 -37.555382,176.763195 -37.881253,177.438813 -37.961248,178.010354 -37.579825,178.517094 -37.695373,178.274731 -38.582813,177.97046 -39.166343,177.206993 -39.145776,176.939981 -39.449736,177.032946 -39.879943,176.885824 -40.065978,176.508017 -40.604808,176.01244 -41.289624,175.239567 -41.688308,175.067898 -41.425895,174.650973 -41.281821,175.22763 -40.459236,174.900157 -39.908933,173.824047 -39.508854,173.852262 -39.146602,174.574802 -38.797683,174.743474 -38.027808,174.697017 -37.381129,174.292028 -36.711092,174.319004 -36.534824,173.840997 -36.121981,173.054171 -35.237125,172.636005 -34.529107,173.007042 -34.450662,173.551298 -35.006183,174.32939 -35.265496,174.612009 -36.156397)))"); + assert_eq!(wkt, "GEOMETRYCOLLECTION(MULTIPOLYGON(((173.020375 -40.919052,173.247234 -41.331999,173.958405 -40.926701,174.247587 -41.349155,174.248517 -41.770008,173.876447 -42.233184,173.22274 -42.970038,172.711246 -43.372288,173.080113 -43.853344,172.308584 -43.865694,171.452925 -44.242519,171.185138 -44.897104,170.616697 -45.908929,169.831422 -46.355775,169.332331 -46.641235,168.411354 -46.619945,167.763745 -46.290197,166.676886 -46.219917,166.509144 -45.852705,167.046424 -45.110941,168.303763 -44.123973,168.949409 -43.935819,169.667815 -43.555326,170.52492 -43.031688,171.12509 -42.512754,171.569714 -41.767424,171.948709 -41.514417,172.097227 -40.956104,172.79858 -40.493962,173.020375 -40.919052)),((174.612009 -36.156397,175.336616 -37.209098,175.357596 -36.526194,175.808887 -36.798942,175.95849 -37.555382,176.763195 -37.881253,177.438813 -37.961248,178.010354 -37.579825,178.517094 -37.695373,178.274731 -38.582813,177.97046 -39.166343,177.206993 -39.145776,176.939981 -39.449736,177.032946 -39.879943,176.885824 -40.065978,176.508017 -40.604808,176.01244 -41.289624,175.239567 -41.688308,175.067898 -41.425895,174.650973 -41.281821,175.22763 -40.459236,174.900157 -39.908933,173.824047 -39.508854,173.852262 -39.146602,174.574802 -38.797683,174.743474 -38.027808,174.697017 -37.381129,174.292028 -36.711092,174.319004 -36.534824,173.840997 -36.121981,173.054171 -35.237125,172.636005 -34.529107,173.007042 -34.450662,173.551298 -35.006183,174.32939 -35.265496,174.612009 -36.156397))))"); Ok(()) } @@ -400,11 +393,11 @@ mod test { let wkt = std::str::from_utf8(&wkt_data).unwrap(); assert_eq!( &wkt[0..100], - "POINT(32.533299524864844 0.583299105614628),POINT(30.27500161597942 0.671004121125236),POINT(15.7989" + "GEOMETRYCOLLECTION(POINT(32.533299524864844 0.583299105614628),POINT(30.27500161597942 0.67100412112" ); assert_eq!( &wkt[wkt.len()-100..], - "06510862875),POINT(103.85387481909902 1.294979325105942),POINT(114.18306345846304 22.30692675357551)" + "6510862875),POINT(103.85387481909902 1.294979325105942),POINT(114.18306345846304 22.30692675357551))" ); Ok(()) } @@ -417,11 +410,11 @@ mod test { let wkt = std::str::from_utf8(&wkt_data).unwrap(); assert_eq!( &wkt[0..100], - "POINT(32.533299524864844 0.583299105614628),POINT(30.27500161597942 0.671004121125236),POINT(15.7989" + "GEOMETRYCOLLECTION(POINT(32.533299524864844 0.583299105614628),POINT(30.27500161597942 0.67100412112" ); assert_eq!( &wkt[wkt.len()-100..], - "06510862875),POINT(103.85387481909902 1.294979325105942),POINT(114.18306345846304 22.30692675357551)" + "6510862875),POINT(103.85387481909902 1.294979325105942),POINT(114.18306345846304 22.30692675357551))" ); Ok(()) } diff --git a/geozero/src/wkt/wkt_writer.rs b/geozero/src/wkt/wkt_writer.rs index 6a34ea1a..a7709c14 100644 --- a/geozero/src/wkt/wkt_writer.rs +++ b/geozero/src/wkt/wkt_writer.rs @@ -178,7 +178,16 @@ impl GeomProcessor for WktWriter<'_, W> { impl PropertyProcessor for WktWriter<'_, W> {} -impl FeatureProcessor for WktWriter<'_, W> {} +impl FeatureProcessor for WktWriter<'_, W> { + // Feature Collections may contain multiple geometries, so we need to wrap + // them in a GeometryCollection to ensure we output valid geometry. + fn dataset_begin(&mut self, _name: Option<&str>) -> Result<()> { + self.geometrycollection_begin(0, 0) + } + fn dataset_end(&mut self) -> Result<()> { + self.geometrycollection_end(0) + } +} #[cfg(test)] mod test {