1use crate::error::ParseError;
4use crate::parser::namespace_detector::NamespaceContext;
5use crate::parser::xml_validator::XmlValidator;
6use ddex_core::models::graph::{
7 ERNMessage, MessageHeader, MessageRecipient, MessageSender, MessageType, Release,
8};
9use ddex_core::models::versions::ERNVersion;
10use quick_xml::events::Event;
11use quick_xml::Reader;
12use std::io::BufRead;
13
14pub struct GraphBuilder {
15 version: ERNVersion,
16}
17
18impl GraphBuilder {
19 pub fn new(version: ERNVersion) -> Self {
20 Self { version }
21 }
22
23 pub fn build_from_xml<R: BufRead + std::io::Seek>(
24 &self,
25 reader: R,
26 ) -> Result<ERNMessage, ParseError> {
27 self.build_from_xml_with_security_config(
28 reader,
29 &crate::parser::security::SecurityConfig::default(),
30 )
31 }
32
33 pub fn build_from_xml_with_security_config<R: BufRead + std::io::Seek>(
34 &self,
35 mut reader: R,
36 _security_config: &crate::parser::security::SecurityConfig,
37 ) -> Result<ERNMessage, ParseError> {
38 let mut xml_reader = Reader::from_reader(&mut reader);
39
40 xml_reader.config_mut().trim_text(true);
42 xml_reader.config_mut().check_end_names = true;
43 xml_reader.config_mut().expand_empty_elements = false;
44
45 let message_header = self.create_minimal_header()?;
47 let mut validator = XmlValidator::strict();
48 let mut releases = Vec::new();
49 let resources = Vec::new(); let parties = Vec::new(); let deals = Vec::new(); let mut buf = Vec::new();
55 let mut in_release_list = false;
56
57 loop {
58 match xml_reader.read_event_into(&mut buf) {
59 Ok(ref event) => {
60 validator.validate_event(event, &xml_reader)?;
62
63 if validator.get_depth() > 100 {
65 return Err(ParseError::DepthLimitExceeded {
66 depth: validator.get_depth(),
67 max: 100,
68 });
69 }
70
71 match event {
72 Event::Start(ref e) => {
73 match e.name().as_ref() {
74 b"ReleaseList" => in_release_list = true,
75 b"Release" if in_release_list => {
76 releases.push(
78 self.parse_minimal_release(
79 &mut xml_reader,
80 &mut validator,
81 )?,
82 );
83 }
84 _ => {}
85 }
86 }
87 Event::End(ref e) => {
88 if e.name().as_ref() == b"ReleaseList" {
89 in_release_list = false;
90 }
91 }
92 Event::Eof => break,
93 _ => {}
94 }
95 }
96 Err(e) => {
97 return Err(ParseError::XmlError {
98 message: format!("XML parsing error: {}", e),
99 location: crate::error::ErrorLocation {
100 line: 0,
101 column: 0,
102 byte_offset: Some(xml_reader.buffer_position() as usize),
103 path: "parser".to_string(),
104 },
105 });
106 }
107 }
108 buf.clear();
109 }
110
111 Ok(ERNMessage {
112 message_header,
113 parties,
114 resources,
115 releases,
116 deals,
117 version: self.version,
118 profile: None,
119 message_audit_trail: None,
120 extensions: None,
121 legacy_extensions: None,
122 comments: None,
123 attributes: None,
124 })
125 }
126
127 pub fn build_from_xml_with_context<R: BufRead + std::io::Seek>(
129 &self,
130 reader: R,
131 _context: NamespaceContext,
132 ) -> Result<ERNMessage, ParseError> {
133 self.build_from_xml_with_context_and_security(
134 reader,
135 _context,
136 &crate::parser::security::SecurityConfig::default(),
137 )
138 }
139
140 pub fn build_from_xml_with_context_and_security<R: BufRead + std::io::Seek>(
141 &self,
142 reader: R,
143 _context: NamespaceContext,
144 security_config: &crate::parser::security::SecurityConfig,
145 ) -> Result<ERNMessage, ParseError> {
146 self.build_from_xml_with_security_config(reader, security_config)
149 }
150
151 fn create_minimal_header(&self) -> Result<MessageHeader, ParseError> {
152 use chrono::Utc;
153
154 Ok(MessageHeader {
156 message_id: format!("MSG_{:?}", self.version),
157 message_type: MessageType::NewReleaseMessage,
158 message_created_date_time: Utc::now(),
159 message_sender: MessageSender {
160 party_id: Vec::new(),
161 party_name: Vec::new(),
162 trading_name: None,
163 extensions: None,
164 attributes: None,
165 comments: None,
166 },
167 message_recipient: MessageRecipient {
168 party_id: Vec::new(),
169 party_name: Vec::new(),
170 trading_name: None,
171 extensions: None,
172 attributes: None,
173 comments: None,
174 },
175 message_control_type: None,
176 message_thread_id: Some("THREAD_001".to_string()),
177 extensions: None,
178 attributes: None,
179 comments: None,
180 })
181 }
182
183 fn parse_minimal_release<R: BufRead>(
184 &self,
185 reader: &mut Reader<R>,
186 validator: &mut crate::parser::xml_validator::XmlValidator,
187 ) -> Result<Release, ParseError> {
188 use ddex_core::models::common::LocalizedString;
189
190 let release = Release {
191 release_reference: format!("R_{:?}", self.version),
193 release_id: Vec::new(),
194 release_title: vec![LocalizedString::new(format!(
195 "Test Release {:?}",
196 self.version
197 ))],
198 release_subtitle: None,
199 release_type: None,
200 genre: Vec::new(),
201 release_resource_reference_list: Vec::new(),
202 display_artist: Vec::new(),
203 party_list: Vec::new(),
204 release_date: Vec::new(),
205 territory_code: Vec::new(),
206 excluded_territory_code: Vec::new(),
207 extensions: None,
208 attributes: None,
209 comments: None,
210 };
211
212 let mut buf = Vec::new();
214 let mut depth = 1;
215 while depth > 0 {
216 match reader.read_event_into(&mut buf) {
217 Ok(ref event) => {
218 validator.validate_event(event, reader)?;
220
221 match event {
222 Event::Start(_) => depth += 1,
223 Event::End(_) => depth -= 1,
224 Event::Eof => break,
225 _ => {}
226 }
227 }
228 Err(e) => {
229 return Err(ParseError::XmlError {
230 message: format!("XML parsing error in release: {}", e),
231 location: crate::error::ErrorLocation {
232 line: 0,
233 column: 0,
234 byte_offset: Some(reader.buffer_position() as usize),
235 path: "parse_minimal_release".to_string(),
236 },
237 });
238 }
239 }
240 buf.clear();
241 }
242
243 Ok(release)
244 }
245}