ddex_parser/parser/
dom.rs

1// core/src/parser/dom.rs
2//! DOM-based parser for smaller DDEX files
3
4use crate::error::ParseError;
5use ddex_core::models::flat::ParsedERNMessage;
6use ddex_core::models::graph::ERNMessage;
7use ddex_core::models::versions::ERNVersion;
8use crate::parser::ParseOptions;
9use crate::parser::namespace_detector::{NamespaceDetector, NamespaceContext};
10use crate::transform::{graph::GraphBuilder, flatten::Flattener};
11use std::io::{BufRead, Seek, SeekFrom};
12use std::time::Instant;
13
14/// Parse using DOM for smaller files
15pub fn parse_dom<R: BufRead + Seek>(
16    mut reader: R,
17    version: ERNVersion,
18    options: ParseOptions,
19) -> Result<ParsedERNMessage, ParseError> {
20    let start = Instant::now();
21    
22    // Check timeout
23    if !options.allow_blocking && options.timeout_ms > 0 {
24        // Would implement timeout checking
25    }
26    
27    // First pass: detect namespaces
28    let mut namespace_detector = NamespaceDetector::new();
29    let namespace_result = namespace_detector.detect_from_xml(&mut reader)?;
30    let namespace_context = NamespaceContext::from_detection_result(namespace_result);
31    
32    // Reset reader for second pass
33    reader.seek(SeekFrom::Start(0))?;
34    
35    // Build graph model from XML with namespace context
36    let graph_builder = GraphBuilder::new(version);
37    let graph = graph_builder.build_from_xml_with_context(reader, namespace_context)?;
38    
39    // Optionally resolve references
40    let graph = if options.resolve_references {
41        resolve_references(graph)?
42    } else {
43        graph
44    };
45    
46    // Flatten to developer-friendly model
47    let flat = Flattener::flatten(graph.clone());
48    
49    // Check elapsed time
50    let elapsed = start.elapsed();
51    if elapsed.as_millis() > options.timeout_ms as u128 {
52        return Err(ParseError::Timeout {
53            seconds: elapsed.as_secs(),
54        });
55    }
56    
57    Ok(ParsedERNMessage {
58        graph,
59        flat,
60        extensions: None,
61    })
62}
63
64fn resolve_references(message: ERNMessage) -> Result<ERNMessage, ParseError> {
65    use crate::transform::resolve::ReferenceResolver;
66    
67    let mut resolver = ReferenceResolver::new();
68    resolver.build_maps(&message);
69    
70    // Check for unresolved references
71    let unresolved = resolver.validate_references(&message);
72    if !unresolved.is_empty() {
73        // Log warnings but don't fail
74        for uref in unresolved {
75            tracing::warn!(
76                "Unresolved reference: {} -> {} at {}",
77                uref.reference_type,
78                uref.reference_value,
79                uref.location
80            );
81        }
82    }
83    
84    Ok(message)
85}