use crate::error::ParseError;
use ddex_core::models::versions::ERNVersion;
use quick_xml::{events::Event, Reader};
use std::io::BufRead;
pub struct VersionDetector;
impl VersionDetector {
pub fn detect<R: std::io::Read>(reader: R) -> crate::error::Result<ERNVersion> {
let mut buf_reader = std::io::BufReader::new(reader);
Self::detect_from_bufread(&mut buf_reader)
}
pub fn detect_from_bufread<R: BufRead>(reader: R) -> crate::error::Result<ERNVersion> {
let mut xml_reader = Reader::from_reader(reader);
xml_reader.config_mut().trim_text(true);
let mut buf = Vec::new();
let mut found_root = false;
let mut namespace_uris = Vec::new();
loop {
match xml_reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) => {
found_root = true;
for attr in e.attributes() {
match attr {
Ok(attr) => {
let key = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
let value = std::str::from_utf8(&attr.value).unwrap_or("");
if key == "xmlns" || key.starts_with("xmlns:") {
namespace_uris.push(value.to_string());
}
}
Err(e) => {
return Err(ParseError::XmlError(format!("Invalid XML attribute: {}", e)));
}
}
}
break; }
Ok(Event::Eof) => {
break;
}
Ok(_) => {} Err(e) => {
return Err(ParseError::XmlError(format!("XML parsing error: {}", e)));
}
}
buf.clear();
}
if !found_root {
return Err(ParseError::XmlError("No root element found - invalid XML".to_string()));
}
for uri in &namespace_uris {
if uri.contains("http://ddex.net/xml/ern/382") {
return Ok(ERNVersion::V3_8_2);
} else if uri.contains("http://ddex.net/xml/ern/42") {
return Ok(ERNVersion::V4_2);
} else if uri.contains("http://ddex.net/xml/ern/43") {
return Ok(ERNVersion::V4_3);
}
}
Err(ParseError::XmlError("No DDEX ERN namespace found - not a valid DDEX document".to_string()))
}
}