Skip to content

Commit f14f15b

Browse files
authored
Merge pull request #2690 from dathere/geoconvert-update
feat: add CSV input and GeoJSONL output to geoconvert, and use buf
2 parents e41a36b + b3e1ce0 commit f14f15b

File tree

1 file changed

+116
-20
lines changed

1 file changed

+116
-20
lines changed

src/cmd/geoconvert.rs

Lines changed: 116 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,43 @@ For example to convert a GeoJSON file into CSV data:
55
66
qsv geoconvert file.geojson geojson csv
77
8+
To convert a CSV file into GeoJSON data, specify the WKT geometry column with the --geometry flag:
9+
10+
qsv geoconvert file.csv csv geojson --geometry geometry
11+
812
Usage:
913
qsv geoconvert [options] (<input>) (<input-format>) (<output-format>)
1014
qsv geoconvert --help
1115
1216
geoconvert REQUIRED arguments:
1317
<input> The spatial file to convert. Does not support stdin.
14-
<input-format> Valid values are "geojson" and "shp"
18+
<input-format> Valid values are "geojson", "shp", and "csv"
1519
<output-format> Valid values are:
16-
- For GeoJSON input: "csv" and "svg"
17-
- For SHP input: "csv" and "geojson"
20+
- For GeoJSON input: "csv", "svg", and "geojsonl"
21+
- For SHP input: "csv", "geojson", and "geojsonl"
22+
- For CSV input: "geojson", "geojsonl", and "svg"
23+
24+
geoconvert options:
25+
REQUIRED FOR CSV INPUT:
26+
-g, --geometry <geometry> The name of the column that has WKT geometry.
1827
1928
Common options:
20-
-h, --help Display this message
21-
-o, --output <file> Write output to <file> instead of stdout.
29+
-h, --help Display this message
30+
-o, --output <file> Write output to <file> instead of stdout.
2231
"#;
2332

2433
use std::{
2534
fs::File,
26-
io::{self, BufWriter, Write},
35+
io::{self, BufReader, BufWriter, Write},
2736
path::Path,
2837
};
2938

30-
use geozero::{ProcessToCsv, ProcessToSvg, csv::CsvWriter, geojson::GeoJsonWriter};
39+
use geozero::{
40+
GeozeroDatasource,
41+
csv::CsvWriter,
42+
geojson::{GeoJsonLineWriter, GeoJsonWriter},
43+
svg::SvgWriter,
44+
};
3145
use serde::Deserialize;
3246

3347
use crate::{CliError, CliResult, util};
@@ -37,7 +51,9 @@ use crate::{CliError, CliResult, util};
3751
#[serde(rename_all = "lowercase")]
3852
enum InputFormat {
3953
Geojson,
54+
// Geojsonl,
4055
Shp,
56+
Csv,
4157
}
4258

4359
/// Supported output formats for spatial data conversion
@@ -47,13 +63,15 @@ enum OutputFormat {
4763
Csv,
4864
Svg,
4965
Geojson,
66+
Geojsonl,
5067
}
5168

5269
#[derive(Deserialize)]
5370
struct Args {
5471
arg_input: Option<String>,
5572
arg_input_format: InputFormat,
5673
arg_output_format: OutputFormat,
74+
flag_geometry: Option<String>,
5775
flag_output: Option<String>,
5876
}
5977

@@ -93,43 +111,121 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
93111
} else {
94112
Box::new(BufWriter::new(stdout.lock()))
95113
};
96-
114+
let mut buf_reader = BufReader::new(File::open(&input_path)?);
115+
// let mut buf_reader = if let Some(input_path) = args.arg_input {
116+
// if input_path == "-" {
117+
// BufReader::new(std::io::stdin())
118+
// }
119+
// } else {
120+
// BufReader::new(std::io::stdin())
121+
// };
97122
// Construct a spatial geometry based on the input format
98-
let output_string = match args.arg_input_format {
123+
match args.arg_input_format {
99124
InputFormat::Geojson => {
100-
let input_string = std::fs::read_to_string(&input_path)?;
101-
let mut geometry = geozero::geojson::GeoJson(&input_string);
125+
let mut geometry = geozero::geojson::GeoJsonReader(&mut buf_reader);
102126
match args.arg_output_format {
103-
OutputFormat::Csv => geometry.to_csv()?,
104-
OutputFormat::Svg => geometry.to_svg()?,
127+
OutputFormat::Csv => {
128+
let mut processor = CsvWriter::new(&mut wtr);
129+
geometry.process(&mut processor)?
130+
},
131+
OutputFormat::Svg => {
132+
let mut processor = SvgWriter::new(&mut wtr, false);
133+
geometry.process(&mut processor)?
134+
},
135+
OutputFormat::Geojsonl => {
136+
let mut processor = GeoJsonLineWriter::new(&mut wtr);
137+
geometry.process(&mut processor)?
138+
},
105139
OutputFormat::Geojson => {
106140
return fail_clierror!("Converting GeoJSON to GeoJSON is not supported");
107141
},
108-
}
142+
};
109143
},
144+
// InputFormat::Geojsonl => {
145+
// let mut geometry = geozero::geojson::GeoJsonLineReader::new(&mut buf_reader);
146+
// match args.arg_output_format {
147+
// OutputFormat::Csv => {
148+
// let mut processor = CsvWriter::new(&mut wtr);
149+
// geometry.process(&mut processor)?
150+
// },
151+
// OutputFormat::Svg => {
152+
// let mut processor = SvgWriter::new(&mut wtr, false);
153+
// geometry.process(&mut processor)?
154+
// },
155+
// OutputFormat::Geojson => {
156+
// let mut processor = GeoJsonWriter::new(&mut wtr);
157+
// geometry.process(&mut processor)?
158+
// },
159+
// OutputFormat::Geojsonl => {
160+
// return fail_clierror!("Converting GeoJSON Lines to GeoJSON Lines is not
161+
// supported"); }
162+
// };
163+
// },
110164
InputFormat::Shp => {
111-
let reader = geozero::shp::ShpReader::from_path(&input_path)
112-
.map_err(|e| CliError::Other(format!("Failed to read SHP file: {e}")))?;
113-
match args.arg_output_format {
165+
let mut reader = geozero::shp::ShpReader::new(&mut buf_reader)?;
166+
let mut input_reader = BufReader::new(File::open(input_path.replace(".shp", ".shx"))?);
167+
let mut dbf_reader = BufReader::new(File::open(input_path.replace(".shp", ".dbf"))?);
168+
reader.add_index_source(&mut input_reader)?;
169+
reader.add_dbf_source(&mut dbf_reader)?;
170+
let output_string = match args.arg_output_format {
114171
OutputFormat::Geojson => {
115172
let mut json: Vec<u8> = Vec::new();
116-
reader.iter_features(&mut GeoJsonWriter::new(&mut json))?;
173+
let _ = reader
174+
.iter_features(&mut GeoJsonWriter::new(&mut json))?
175+
.collect::<Vec<_>>();
176+
String::from_utf8(json)
177+
.map_err(|e| CliError::Other(format!("Invalid UTF-8 in output: {e}")))?
178+
},
179+
OutputFormat::Geojsonl => {
180+
let mut json: Vec<u8> = Vec::new();
181+
let _ = reader
182+
.iter_features(&mut GeoJsonLineWriter::new(&mut json))?
183+
.collect::<Vec<_>>();
117184
String::from_utf8(json)
118185
.map_err(|e| CliError::Other(format!("Invalid UTF-8 in output: {e}")))?
119186
},
120187
OutputFormat::Csv => {
121188
let mut csv: Vec<u8> = Vec::new();
122-
reader.iter_features(&mut CsvWriter::new(&mut csv))?;
189+
let _ = reader
190+
.iter_features(&mut CsvWriter::new(&mut csv))?
191+
.collect::<Vec<_>>();
123192
String::from_utf8(csv)
124193
.map_err(|e| CliError::Other(format!("Invalid UTF-8 in output: {e}")))?
125194
},
126195
OutputFormat::Svg => {
127196
return fail_clierror!("Converting SHP to SVG is not supported");
128197
},
198+
};
199+
wtr.write_all(output_string.as_bytes())?;
200+
},
201+
InputFormat::Csv => {
202+
if let Some(geometry_col) = args.flag_geometry {
203+
let mut csv = geozero::csv::CsvReader::new(&geometry_col, buf_reader);
204+
match args.arg_output_format {
205+
OutputFormat::Geojson => {
206+
let mut processor = GeoJsonWriter::new(&mut wtr);
207+
csv.process(&mut processor)?;
208+
},
209+
OutputFormat::Geojsonl => {
210+
let mut processor = GeoJsonLineWriter::new(&mut wtr);
211+
csv.process(&mut processor)?
212+
},
213+
OutputFormat::Svg => {
214+
let mut processor = SvgWriter::new(&mut wtr, false);
215+
csv.process(&mut processor)?;
216+
},
217+
OutputFormat::Csv => {
218+
return fail_clierror!("Converting CSV to CSV is not supported");
219+
},
220+
};
221+
} else {
222+
return fail_clierror!(
223+
"Please specify a geometry column with the --geometry option"
224+
);
129225
}
130226
},
131227
};
132228

133-
wtr.write_all(output_string.as_bytes())?;
229+
// wtr.write_all(output_string.as_bytes())?;
134230
Ok(wtr.flush()?)
135231
}

0 commit comments

Comments
 (0)