feedparser_rs/parser/
mod.rs

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