feed_parser/parsers/rss1/
mod.rs1use crate::parsers::{
2 Feed,
3 errors::{ParseError, ParseResult},
4 internal::{TextRun, compile_tag_patterns, deserialize_feed, escape_inline_html},
5};
6use core::str;
7use quick_xml::Reader;
8use quick_xml::Writer;
9use quick_xml::events::{BytesEnd, BytesStart, Event};
10use regex::Regex;
11use std::io::Cursor;
12use std::sync::LazyLock;
13
14#[cfg(test)]
15mod tests;
16
17static HTML_BEARING_TAGS: LazyLock<Vec<(&'static str, Regex)>> =
19 LazyLock::new(|| compile_tag_patterns(&["title", "description", "summary", "content"]));
20
21pub fn parse(text: &str) -> ParseResult<Vec<Feed>> {
29 let text = escape_inline_html(text, &HTML_BEARING_TAGS);
30
31 let mut reader = Reader::from_str(&text);
32
33 let mut feeds = Vec::new();
34 let mut writer = Writer::new(Cursor::new(Vec::new()));
35 let mut run = TextRun::default();
38 let mut parsing = false;
39 loop {
40 match reader.read_event()? {
41 Event::Start(e) => {
42 run.flush(&mut writer)?;
43 if parsing {
44 if e.name().as_ref() == b"dc:creator" {
45 writer.write_event(Event::Start(BytesStart::new("creator")))?;
46 } else if e.name().as_ref() == b"dc:date" {
47 writer.write_event(Event::Start(BytesStart::new("date")))?;
48 } else if e.name().as_ref() == b"pubDate" {
49 writer.write_event(Event::Start(BytesStart::new("publish_date")))?;
50 } else {
51 writer.write_event(Event::Start(e.clone()))?;
52 }
53 }
54 if e.name().as_ref() == b"item" {
55 writer.write_event(Event::Start(BytesStart::new("item")))?;
56 parsing = true;
57 }
58 }
59 Event::End(e) => {
60 run.flush(&mut writer)?;
61 if parsing && e.name().as_ref() == b"item" {
62 writer.write_event(Event::End(BytesEnd::new("item")))?;
63 let feed_text = writer.into_inner().into_inner();
64 feeds.push(deserialize_feed(str::from_utf8(&feed_text)?)?);
65
66 writer = Writer::new(Cursor::new(Vec::new()));
67 parsing = false;
68 } else if parsing {
69 if e.name().as_ref() == b"dc:creator" {
70 writer.write_event(Event::End(BytesEnd::new("creator")))?;
71 } else if e.name().as_ref() == b"dc:date" {
72 writer.write_event(Event::End(BytesEnd::new("date")))?;
73 } else if e.name().as_ref() == b"pubDate" {
74 writer.write_event(Event::End(BytesEnd::new("publish_date")))?;
75 } else {
76 writer.write_event(Event::End(e))?;
77 }
78 }
79 }
80 Event::Text(e) => {
81 if parsing {
82 run.push(Event::Text(e));
83 }
84 }
85 Event::CData(e) => {
86 if parsing {
87 run.push(Event::CData(e));
88 }
89 }
90 Event::GeneralRef(e) => {
93 if parsing {
94 run.push(Event::GeneralRef(e));
95 }
96 }
97 Event::Eof => break,
98 _ => {}
99 }
100 }
101
102 if parsing {
103 return Err(ParseError::InvalidFeedFormat(
104 "reached end of document inside an unclosed <item> element".to_string(),
105 ));
106 }
107
108 Ok(feeds)
109}