ddex_parser/parser/
mod.rs

1// core/src/parser/mod.rs
2//! Parser module
3
4pub mod attribute_extractor;
5pub mod detector;
6pub mod dom;
7pub mod extension_capture;
8pub mod mode;
9pub mod multi_release_parser;
10pub mod namespace_detector;
11pub mod security;
12pub mod selective_parser;
13pub mod stream;
14pub mod xml_validator;
15pub mod xpath_selector;
16
17#[cfg(test)]
18mod tests;
19
20use crate::error::ParseError;
21use ddex_core::models::flat::ParsedERNMessage;
22use std::io::BufRead;
23
24/// Main parser options
25#[derive(Debug, Clone, PartialEq)]
26pub struct ParseOptions {
27    pub mode: mode::ParseMode,
28    pub auto_threshold: u64,
29    pub resolve_references: bool,
30    pub include_raw: bool,
31    pub max_memory: usize,
32    pub timeout_ms: u64,
33    pub allow_blocking: bool,
34    pub include_raw_extensions: bool,
35    pub include_comments: bool,
36    pub preserve_unknown_elements: bool,
37    pub chunk_size: usize,
38}
39
40impl Default for ParseOptions {
41    fn default() -> Self {
42        Self {
43            mode: mode::ParseMode::Auto,
44            auto_threshold: 10 * 1024 * 1024, // 10MB
45            resolve_references: true,
46            include_raw: false,
47            max_memory: 100 * 1024 * 1024, // 100MB
48            timeout_ms: 30000,             // 30 seconds
49            allow_blocking: false,
50            chunk_size: 100,
51            include_raw_extensions: false,
52            include_comments: false,
53            preserve_unknown_elements: false,
54        }
55    }
56}
57
58/// Parse DDEX XML with automatic mode selection
59pub fn parse<R: BufRead + std::io::Seek>(
60    mut reader: R,
61    options: ParseOptions,
62    security_config: &security::SecurityConfig,
63) -> Result<ParsedERNMessage, ParseError> {
64    // Detect version first - this now validates XML
65    let version = detector::VersionDetector::detect(&mut reader)?;
66    reader.seek(std::io::SeekFrom::Start(0))?;
67
68    // Select parsing mode
69    let mode_selector = mode::ModeSelector::new(options.auto_threshold);
70    let selected_mode = mode_selector.select_mode(&mut reader, options.mode)?;
71    reader.seek(std::io::SeekFrom::Start(0))?;
72
73    match selected_mode {
74        mode::ParseMode::Dom => {
75            // Use DOM parser for smaller files
76            dom::parse_dom(reader, version, options, security_config)
77        }
78        mode::ParseMode::Stream => {
79            // Use streaming parser for larger files
80            stream::parse_streaming(reader, version, options, security_config)
81        }
82        mode::ParseMode::Auto => unreachable!(), // Already resolved
83    }
84}
85
86pub mod version_ext;
87
88impl ParseOptions {
89    pub fn with_extensions() -> Self {
90        Self {
91            include_raw_extensions: true,
92            include_comments: true,
93            preserve_unknown_elements: true,
94            ..Default::default()
95        }
96    }
97
98    pub fn for_round_trip() -> Self {
99        Self {
100            include_raw_extensions: true,
101            include_comments: true,
102            preserve_unknown_elements: true,
103            resolve_references: false,
104            ..Default::default()
105        }
106    }
107}