ddex_parser/parser/
detector.rs

1use crate::error::{ErrorLocation, ParseError};
2use ddex_core::models::versions::ERNVersion;
3use quick_xml::{events::Event, Reader};
4use std::io::BufRead;
5// core/src/parser/detector.rs
6
7pub struct VersionDetector;
8
9impl VersionDetector {
10    pub fn detect<R: std::io::Read>(reader: R) -> crate::error::Result<ERNVersion> {
11        let mut buf_reader = std::io::BufReader::new(reader);
12        Self::detect_from_bufread(&mut buf_reader)
13    }
14
15    pub fn detect_from_bufread<R: BufRead>(reader: R) -> crate::error::Result<ERNVersion> {
16        let mut xml_reader = Reader::from_reader(reader);
17        xml_reader.config_mut().trim_text(true);
18
19        let mut buf = Vec::new();
20        let mut found_root = false;
21        let mut namespace_uris = Vec::new();
22
23        // Parse XML and collect namespace URIs from the root element
24        loop {
25            match xml_reader.read_event_into(&mut buf) {
26                Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) => {
27                    found_root = true;
28
29                    // Extract namespace URIs from attributes
30                    for attr in e.attributes() {
31                        match attr {
32                            Ok(attr) => {
33                                let key = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
34                                let value = std::str::from_utf8(&attr.value).unwrap_or("");
35
36                                // Look for xmlns declarations
37                                if key == "xmlns" || key.starts_with("xmlns:") {
38                                    namespace_uris.push(value.to_string());
39                                }
40                            }
41                            Err(e) => {
42                                return Err(ParseError::XmlError {
43                                    message: format!("Invalid XML attribute: {}", e),
44                                    location: ErrorLocation::default(),
45                                });
46                            }
47                        }
48                    }
49                    break; // Only need the root element
50                }
51                Ok(Event::Eof) => {
52                    break;
53                }
54                Ok(_) => {} // Skip other events
55                Err(e) => {
56                    return Err(ParseError::XmlError {
57                        message: format!("XML parsing error: {}", e),
58                        location: ErrorLocation::default(),
59                    });
60                }
61            }
62            buf.clear();
63        }
64
65        // If no root element found, it's invalid XML
66        if !found_root {
67            return Err(ParseError::XmlError {
68                message: "No root element found - invalid XML".to_string(),
69                location: ErrorLocation::default(),
70            });
71        }
72
73        // Check for DDEX ERN version in namespace URIs
74        for uri in &namespace_uris {
75            if uri.contains("http://ddex.net/xml/ern/382") {
76                return Ok(ERNVersion::V3_8_2);
77            } else if uri.contains("http://ddex.net/xml/ern/42") {
78                return Ok(ERNVersion::V4_2);
79            } else if uri.contains("http://ddex.net/xml/ern/43") {
80                return Ok(ERNVersion::V4_3);
81            }
82        }
83
84        // If no DDEX ERN namespace found, it's not a valid DDEX document
85        Err(ParseError::XmlError {
86            message: "No DDEX ERN namespace found - not a valid DDEX document".to_string(),
87            location: ErrorLocation::default(),
88        })
89    }
90}