use std::io::BufRead; use quick_xml::de::from_str; use quick_xml::events::{BytesStart, Event}; use quick_xml::reader::Reader; use quick_xml::Writer; use xmltv::*; /// Reads from a start tag all the way to the corresponding end tag, returns the bytes of the whole tag fn read_to_end_into_buffer( reader: &mut Reader, start_tag: &BytesStart, junk_buf: &mut Vec, ) -> Result, quick_xml::Error> { let mut depth = 0; let mut output_buf: Vec = Vec::new(); let mut w = Writer::new(&mut output_buf); let tag_name = start_tag.name(); w.write_event(Event::Start(start_tag.clone()))?; loop { junk_buf.clear(); let event = reader.read_event_into(junk_buf)?; w.write_event(&event)?; match event { Event::Start(e) if e.name() == tag_name => depth += 1, Event::End(e) if e.name() == tag_name => { if depth == 0 { return Ok(output_buf); } depth -= 1; } Event::Eof => { panic!("oh no") } _ => {} } } } /// Expect to read without error #[test] fn test_read_from_files() { println!("Testing with: example_1.xml"); let content = std::fs::read_to_string("tests/example_1.xml").unwrap(); let _result: Tv = from_str(&content).unwrap(); println!("Testing with: xmltv_fr.xml"); let content = std::fs::read_to_string("tests/xmltv_fr.xml").unwrap(); let _result: Tv = from_str(&content).unwrap(); } /// Read programme by programme to get where the error is in it because serde error is not very helpful #[test] fn test_programmes_from_files() { let xml = std::fs::read_to_string("tests/xmltv_fr.xml").unwrap(); let mut reader = Reader::from_str(&xml); reader.trim_text(true); // let mut count = 1u16; let mut buf = Vec::new(); let mut junk_buf: Vec = Vec::new(); // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s) loop { // NOTE: this is the generic case when we don't know about the input BufRead. // when the input is a &str or a &[u8], we don't actually need to use another // buffer, we could directly call `reader.read_event()` match reader.read_event_into(&mut buf) { Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e), // exits the loop when reaching end of file Ok(Event::Eof) => break, Ok(Event::Start(e)) => { if e.name().as_ref() == b"programme" { let release_bytes = read_to_end_into_buffer(&mut reader, &e, &mut junk_buf).unwrap(); let content = std::str::from_utf8(&release_bytes).unwrap(); // println!("\n\nReading programme #{}", count); // println!("{}", content); let _result: Programme = from_str(content).unwrap(); // count += 1; } } Ok(Event::Text(e)) => println!("Text: {}", e.unescape().unwrap()), // There are several other `Event`s we do not consider here _ => (), } // if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low buf.clear(); } }