ddex_parser/parser/
dom.rs1use 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
14pub 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 if !options.allow_blocking && options.timeout_ms > 0 {
24 }
26
27 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 reader.seek(SeekFrom::Start(0))?;
34
35 let graph_builder = GraphBuilder::new(version);
37 let graph = graph_builder.build_from_xml_with_context(reader, namespace_context)?;
38
39 let graph = if options.resolve_references {
41 resolve_references(graph)?
42 } else {
43 graph
44 };
45
46 let flat = Flattener::flatten(graph.clone());
48
49 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 let unresolved = resolver.validate_references(&message);
72 if !unresolved.is_empty() {
73 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}