feedparser_rs/parser/
mod.rs

1pub mod atom;
2mod common;
3mod detect;
4pub mod json;
5pub mod namespace_detection;
6pub mod rss;
7pub mod rss10;
8
9use crate::{error::Result, types::ParsedFeed};
10
11pub use common::skip_element;
12pub use detect::detect_format;
13
14/// Parse feed from raw bytes
15///
16/// This is the main entry point for parsing feeds. It automatically detects
17/// the feed format (RSS, Atom, JSON) and parses accordingly.
18///
19/// # Errors
20///
21/// Returns a `FeedError` if the feed cannot be parsed. However, in most cases,
22/// the parser will set the `bozo` flag and return partial results rather than
23/// returning an error.
24///
25/// # Examples
26///
27/// ```
28/// use feedparser_rs::parse;
29///
30/// let xml = r#"
31///     <?xml version="1.0"?>
32///     <rss version="2.0">
33///         <channel>
34///             <title>Example Feed</title>
35///         </channel>
36///     </rss>
37/// "#;
38///
39/// let feed = parse(xml.as_bytes()).unwrap();
40/// assert_eq!(feed.feed.title.as_deref(), Some("Example Feed"));
41/// ```
42pub fn parse(data: &[u8]) -> Result<ParsedFeed> {
43    parse_with_limits(data, crate::ParserLimits::default())
44}
45
46/// Parse feed with custom parser limits
47///
48/// This allows controlling resource usage when parsing untrusted feeds.
49///
50/// # Examples
51///
52/// ```
53/// use feedparser_rs::{parse_with_limits, ParserLimits};
54///
55/// let xml = b"<rss version=\"2.0\"><channel><title>Test</title></channel></rss>";
56/// let limits = ParserLimits::strict();
57/// let feed = parse_with_limits(xml, limits).unwrap();
58/// ```
59///
60/// # Errors
61///
62/// Returns an error if:
63/// - Feed size exceeds limits
64/// - Format is unknown or unsupported
65/// - Fatal parsing error occurs
66pub fn parse_with_limits(data: &[u8], limits: crate::ParserLimits) -> Result<ParsedFeed> {
67    use crate::types::FeedVersion;
68
69    // Detect format
70    let version = detect_format(data);
71
72    // Parse based on detected format
73    match version {
74        // RSS variants (all use RSS 2.0 parser for now)
75        FeedVersion::Rss20 | FeedVersion::Rss092 | FeedVersion::Rss091 | FeedVersion::Rss090 => {
76            rss::parse_rss20_with_limits(data, limits)
77        }
78
79        // Atom variants
80        FeedVersion::Atom10 | FeedVersion::Atom03 => atom::parse_atom10_with_limits(data, limits),
81
82        // RSS 1.0 (RDF)
83        FeedVersion::Rss10 => rss10::parse_rss10_with_limits(data, limits),
84
85        // JSON Feed
86        FeedVersion::JsonFeed10 | FeedVersion::JsonFeed11 => {
87            json::parse_json_feed_with_limits(data, limits)
88        }
89
90        // Unknown format - try RSS first (most common)
91        FeedVersion::Unknown => {
92            // Try RSS first
93            if let Ok(feed) = rss::parse_rss20_with_limits(data, limits) {
94                return Ok(feed);
95            }
96
97            // Try Atom
98            atom::parse_atom10_with_limits(data, limits)
99        }
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn test_parse_returns_ok() {
109        let result = parse(b"test");
110        assert!(result.is_ok());
111    }
112}