I'm a Rust beginner and am coding my first Rust program: a weather app that gets the weather for 10 locations across Canada as XML data from the Canadian government meteorological site. I'm writing this program in stages. Stage 1 reads in a CSV file with the cities and the corresponding URLs of the XML files. This now works in Rust. Stage 2 is to see that the program can indeed retrieve the files and read through them line by line. Stage 3 is to fine tune this and extract the info for displaying current temperate, current conditions, high, low, and either Humidex or Windchill temperature.
The problem occurs in Stage 2, in the fn fetch_and_parse_xml. I've passed in the two strings for City name and associated URL. On the line before the get(url)? I print out the two strings and the URL is fully formed, with its base. As soon as it tries to get the file I get the error message: "Error: builder error: relative URL without a base"
Here is my unfinished program:
1 use std::path::Path;
2 use csv::ReaderBuilder;
3 use reqwest::blocking::get;
4 use std::io::BufRead;
5 use std::io::BufReader;
6
7
8 struct Site {
9 city: String,
10 url: String,
11 }
12
13 fn main() -> Result<(), Box<(dyn std::error::Error + 'static)>> {
14 let path=Path::new("weather-sites.csv");
15 let mut reader = ReaderBuilder::new().from_path(&path)?;
16
17 let mut sites = Vec::new();
18
19 for result in reader.records() {
20 let record = result?;
21 let city = record.get(0).unwrap_or("").to_string();
22 let url = record.get(1).unwrap_or("").to_string();
23
24 sites.push(Site {city, url});
25 }
26
27 for site in &sites {
28 let city_name = &site.city;
29 let city_url = &site.url;
30 // println!("City: {}, URL: {}", city_name, city_url);
31 if let Err(e) = fetch_and_parse_xml(city_name, city_url) {
32 eprintln!("Error: {}", e);
33 }
34
35 }
36
37 Ok(())
38 }
39
40
41 fn fetch_and_parse_xml(city: &str, url: &str) -> Result<(), Box<dyn std::error::Error>> {
42 // Check the incoming
43 println!("{}, {}", city, url);
44 // Fetch the XML file from the internet
45 let response = get(url)?;
46
47 // Check if the request was successful
48 if !response.status().is_success() {
49 return Err(format!("Failed to fetch XML file for city {}: {}", city, response.status()).into(
50 }
51
52 // Read the XML file line by line
53 let reader = BufReader::new(response);
54 for line in reader.lines() {
55 let line = line?;
56 println!("{}", line);
57 }
58
59 Ok(())
60 }
I've based this on sample programs I've seen on the Net and attempted to modify them for my use. I may be missing something basic.
I have this app working in both Python and PHP, but wanted to see if I could replicate it in Rust.
This is the current output:
'Ladysmith', 'https://dd.weather.gc.ca/citypage_weather/xml/BC/s0000496_e.xml'
Error: builder error: relative URL without a base
'Kelowna', 'https://dd.weather.gc.ca/citypage_weather/xml/BC/s0000592_e.xml'
Error: builder error: relative URL without a base
'Arnprior', 'https://dd.weather.gc.ca/citypage_weather/xml/BC/s0000592_e.xml'
Error: builder error: relative URL without a base
'Ottawa', 'https://dd.weather.gc.ca/citypage_weather/xml/ON/s0000430_e.xml'
Error: builder error: relative URL without a base
'Sauble', 'https://dd.weather.gc.ca/citypage_weather/xml/ON/s0000724_e.xml'
Error: builder error: relative URL without a base
'Guelph', 'https://dd.weather.gc.ca/citypage_weather/xml/BC/s0000592_e.xml'
Error: builder error: relative URL without a base
'Hamilton', 'https://dd.weather.gc.ca/citypage_weather/xml/ON/s0000549_e.xml'
Error: builder error: relative URL without a base
'St_Catherines', 'https://dd.weather.gc.ca/citypage_weather/xml/ON/s0000691_e.xml'
Error: builder error: relative URL without a base
'Toronto', 'https://dd.weather.gc.ca/citypage_weather/xml/ON/s0000458_e.xml'
Error: builder error: relative URL without a base
'Mississauga', 'https://dd.weather.gc.ca/citypage_weather/xml/ON/s0000786_e.xml'
Error: builder error: relative URL without a base