Skip to content

Commit 4f8b26f

Browse files
committed
Add Table type and function to parse cols declarations
1 parent 29ddc7e commit 4f8b26f

File tree

1 file changed

+87
-43
lines changed

1 file changed

+87
-43
lines changed

src/main.rs

Lines changed: 87 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,42 @@
11
extern crate quick_xml;
22
extern crate yaml_rust;
33

4-
use std::io::Read;
4+
use std::io::{Read, Write, stdout};
55
use std::fs::File;
6+
use std::path::Path;
67
use std::env;
78
use std::time::Instant;
89
use quick_xml::Reader;
910
use quick_xml::events::Event;
1011
use yaml_rust::YamlLoader;
12+
use yaml_rust::yaml::Yaml;
13+
14+
struct Table<'a> {
15+
path: String,
16+
file: Box<dyn Write>,
17+
columns: Vec<Column<'a>>
18+
}
19+
impl<'a> Table<'a> {
20+
fn new<'b>(path: &str, file: Option<&str>) -> Table<'b> {
21+
Table {
22+
path: String::from(path),
23+
file: match file {
24+
None => Box::new(stdout()),
25+
Some(ref file) => Box::new(File::create(&Path::new(file)).unwrap())
26+
},
27+
columns: Vec::new()
28+
}
29+
}
30+
}
1131

12-
#[derive(Debug)]
1332
struct Column<'a> {
1433
name: String,
1534
path: String,
1635
value: String,
1736
convert: Option<&'a str>,
1837
search: Option<&'a str>,
1938
replace: Option<&'a str>,
39+
consol: Option<&'a str>
2040
}
2141

2242
struct Geometry {
@@ -61,11 +81,27 @@ fn gml_to_ewkb(value: &mut String, geom: &Geometry) {
6181
}
6282
}
6383

64-
fn main() {
84+
fn add_table<'a>(tables: &mut Vec<Table<'a>>, rowpath: &str, outfile: Option<&str>, colspec: &'a Vec<Yaml>) {
85+
tables.push(Table::new(rowpath, outfile));
86+
let table = tables.last_mut().unwrap();
87+
for col in colspec {
88+
let name = col["name"].as_str().expect("Column has no 'name' entry in configuration file");
89+
let colpath = col["path"].as_str().expect("Column has no 'path' entry in configuration file");
90+
let convert = col["convert"].as_str();
91+
let search = col["search"].as_str();
92+
let replace = col["replace"].as_str();
93+
let consol = col["consol"].as_str();
94+
let mut path = String::from(rowpath);
95+
path.push_str(colpath);
96+
table.columns.push(Column { name: name.to_string(), path, value: String::new(), convert, search, replace, consol });
97+
}
98+
}
99+
100+
fn main() -> std::io::Result<()> {
65101
let args: Vec<_> = env::args().collect();
66102
if args.len() != 3 {
67103
eprintln!("usage: {} <configfile> <xmlfile>", args[0]);
68-
return;
104+
return Ok(());
69105
}
70106

71107
let mut config_str = String::new();
@@ -78,23 +114,14 @@ fn main() {
78114

79115
let mut path = String::new();
80116
let mut buf = Vec::new();
81-
82117
let mut count = 0;
83118

84-
let rowpath = config["rowpath"].as_str().expect("No valid 'rowpath' entry in configuration file");
85-
let colspec = config["columns"].as_vec().expect("No valid 'columns' array in configuration file");
86-
let mut columns = Vec::new();
87-
88-
for col in colspec {
89-
let name = col["name"].as_str().expect("Column has no 'name' entry in configuration file");
90-
let colpath = col["path"].as_str().expect("Column has no 'path' entry in configuration file");
91-
let convert = col["convert"].as_str();
92-
let search = col["search"].as_str();
93-
let replace = col["replace"].as_str();
94-
let mut path = String::from(rowpath);
95-
path.push_str(colpath);
96-
columns.push(Column { name: name.to_string(), path, value: String::new(), convert, search, replace });
97-
}
119+
let rowpath = config["path"].as_str().expect("No valid 'rowpath' entry in configuration file");
120+
let colspec = config["cols"].as_vec().expect("No valid 'columns' array in configuration file");
121+
let outfile = config["file"].as_str();
122+
let mut tables: Vec<Table> = Vec::new();
123+
add_table(&mut tables, rowpath, outfile, colspec);
124+
let table = tables.first_mut().unwrap();
98125

99126
let mut xmltotext = false;
100127
let mut text = String::new();
@@ -155,13 +182,13 @@ fn main() {
155182
}
156183
continue;
157184
}
158-
else if path == rowpath {
185+
else if path == table.path {
159186
count += 1;
160187
}
161-
else if path.len() > rowpath.len() {
162-
for i in 0..columns.len() {
163-
if path == columns[i].path {
164-
match columns[i].convert {
188+
else if path.len() > table.path.len() {
189+
for i in 0..table.columns.len() {
190+
if path == table.columns[i].path {
191+
match table.columns[i].convert {
165192
None => (),
166193
Some("xml-to-text") => xmltotext = true,
167194
Some("gml-to-ewkb") => gmltoewkb = true,
@@ -186,48 +213,64 @@ fn main() {
186213
}
187214
continue;
188215
}
189-
for i in 0..columns.len() {
190-
if path == columns[i].path {
191-
columns[i].value.push_str(&e.unescape_and_decode(&reader).unwrap().replace("\\", "\\\\"));
216+
for i in 0..table.columns.len() {
217+
if path == table.columns[i].path {
218+
match table.columns[i].consol {
219+
None => {
220+
if !table.columns[i].value.is_empty() {
221+
eprintln!("Column '{}' has multiple occurrences without a consolidation method; using 'first'", table.columns[i].name);
222+
break;
223+
}
224+
},
225+
Some("append") => {
226+
if !table.columns[i].value.is_empty() { table.columns[i].value.push(','); }
227+
},
228+
Some(s) => {
229+
eprintln!("Column '{}' has invalid consolidation method {}", table.columns[i].name, s);
230+
break;
231+
}
232+
}
233+
table.columns[i].value.push_str(&e.unescape_and_decode(&reader).unwrap().replace("\\", "\\\\"));
234+
break;
192235
}
193236
}
194237
},
195238
Ok(Event::End(_)) => {
196-
if path == rowpath {
197-
for i in 0..columns.len() {
198-
if i > 0 { print!("\t"); }
199-
if columns[i].value.is_empty() { print!("\\N"); }
239+
if path == table.path {
240+
for i in 0..table.columns.len() {
241+
if i > 0 { write!(table.file, "\t")?; }
242+
if table.columns[i].value.is_empty() { write!(table.file, "\\N")?; }
200243
else {
201-
if let (Some(s), Some(r)) = (columns[i].search, columns[i].replace) {
202-
columns[i].value = columns[i].value.replace(s, r);
244+
if let (Some(s), Some(r)) = (table.columns[i].search, table.columns[i].replace) {
245+
table.columns[i].value = table.columns[i].value.replace(s, r);
203246
}
204-
print!("{}", columns[i].value);
205-
columns[i].value.clear();
247+
write!(table.file, "{}", table.columns[i].value)?;
248+
table.columns[i].value.clear();
206249
}
207250
}
208-
println!("");
251+
writeln!(table.file)?;
209252
}
210253
let i = path.rfind('/').unwrap();
211254
let tag = path.split_off(i);
212255
if xmltotext {
213256
text.push_str(&format!("<{}>", tag));
214-
for i in 0..columns.len() {
215-
if path == columns[i].path {
257+
for i in 0..table.columns.len() {
258+
if path == table.columns[i].path {
216259
xmltotext = false;
217-
if let (Some(s), Some(r)) = (columns[i].search, columns[i].replace) {
260+
if let (Some(s), Some(r)) = (table.columns[i].search, table.columns[i].replace) {
218261
text = text.replace(s, r);
219262
}
220-
columns[i].value.push_str(&text);
263+
table.columns[i].value.push_str(&text);
221264
text.clear();
222265
break;
223266
}
224267
}
225268
}
226269
else if gmltoewkb {
227-
for i in 0..columns.len() {
228-
if path == columns[i].path {
270+
for i in 0..table.columns.len() {
271+
if path == table.columns[i].path {
229272
gmltoewkb = false;
230-
gml_to_ewkb(&mut columns[i].value, &gmlgeom);
273+
gml_to_ewkb(&mut table.columns[i].value, &gmlgeom);
231274
gmlgeom.reset();
232275
break;
233276
}
@@ -241,4 +284,5 @@ fn main() {
241284
buf.clear();
242285
}
243286
eprintln!("{} rows processed in {} seconds", count, start.elapsed().as_secs());
287+
Ok(())
244288
}

0 commit comments

Comments
 (0)