ddex_builder/generator/
mod.rs1pub mod xml_writer;
75pub mod optimized_xml_writer;
76
77use crate::ast::{AST, Element}; use crate::builder::{BuildRequest, ReleaseRequest};
79use crate::error::BuildError;
80use indexmap::IndexMap;
81
82pub struct ASTGenerator {
83 version: String,
84}
85
86impl ASTGenerator {
87 pub fn new(version: String) -> Self {
88 Self { version }
89 }
90
91 pub fn generate(&mut self, request: &BuildRequest) -> Result<AST, BuildError> {
92 let mut root = Element::new("NewReleaseMessage");
94 root.namespace = Some("ern".to_string());
95
96 root.attributes.insert(
98 "MessageSchemaVersionId".to_string(),
99 format!("ern/{}", self.version),
100 );
101
102 root.add_child(self.generate_message_header(request)?);
104
105 root.add_child(self.generate_resource_list(&request.releases)?);
107
108 root.add_child(self.generate_release_list(&request.releases)?);
110
111 let mut namespaces = IndexMap::new();
113 namespaces.insert("ern".to_string(), format!("http://ddex.net/xml/ern/{}", self.version.replace('.', "")));
114 namespaces.insert("xsi".to_string(), "http://www.w3.org/2001/XMLSchema-instance".to_string());
115
116 Ok(AST {
117 root,
118 namespaces,
119 schema_location: None,
120 })
121 }
122
123 fn generate_message_header(&self, request: &BuildRequest) -> Result<Element, BuildError> {
124 let mut header = Element::new("MessageHeader");
125
126 if let Some(ref msg_id) = request.header.message_id {
128 header.add_child(Element::new("MessageThreadId").with_text(msg_id));
129 header.add_child(Element::new("MessageId").with_text(msg_id));
130 }
131
132 let created_time = request.header.message_created_date_time
134 .as_ref()
135 .map(|t| t.clone())
136 .unwrap_or_else(|| chrono::Utc::now().to_rfc3339());
137
138 header.add_child(
139 Element::new("MessageCreatedDateTime")
140 .with_text(created_time)
141 );
142
143 header.add_child(self.generate_party("MessageSender", &request.header.message_sender)?);
145
146 header.add_child(self.generate_party("MessageRecipient", &request.header.message_recipient)?);
148
149 Ok(header)
150 }
151
152 fn generate_party(&self, element_name: &str, party: &crate::builder::PartyRequest) -> Result<Element, BuildError> {
153 let mut party_elem = Element::new(element_name);
154
155 if let Some(ref party_id) = party.party_id {
157 party_elem.add_child(Element::new("PartyId").with_text(party_id));
158 }
159
160 if let Some(ref party_ref) = party.party_reference {
162 party_elem.add_child(Element::new("PartyReference").with_text(party_ref));
163 }
164
165 for party_name in &party.party_name {
167 let mut name_elem = Element::new("PartyName");
168 if let Some(ref lang) = party_name.language_code {
169 name_elem.attributes.insert("LanguageCode".to_string(), lang.clone());
170 }
171 name_elem.add_text(&party_name.text);
172 party_elem.add_child(name_elem);
173 }
174
175 Ok(party_elem)
176 }
177
178 fn generate_resource_list(&self, releases: &[ReleaseRequest]) -> Result<Element, BuildError> {
179 let mut resource_list = Element::new("ResourceList");
180
181 for release in releases {
183 for track in &release.tracks {
184 let mut sound_recording = Element::new("SoundRecording");
185
186 let resource_ref = track.resource_reference.clone()
189 .unwrap_or_else(|| format!("A{}", track.track_id));
190 sound_recording.add_child(
191 Element::new("ResourceReference").with_text(&resource_ref)
192 );
193
194 let mut resource_id = Element::new("ResourceId");
196 resource_id.add_child(Element::new("ISRC").with_text(&track.isrc));
197 sound_recording.add_child(resource_id);
198
199 let mut ref_title = Element::new("ReferenceTitle");
201 ref_title.add_child(Element::new("TitleText").with_text(&track.title));
202 sound_recording.add_child(ref_title);
203
204 sound_recording.add_child(
206 Element::new("Duration").with_text(&track.duration)
207 );
208
209 resource_list.add_child(sound_recording);
210 }
211 }
212
213 Ok(resource_list)
214 }
215
216 fn generate_release_list(&self, releases: &[ReleaseRequest]) -> Result<Element, BuildError> {
217 let mut release_list = Element::new("ReleaseList");
218
219 for release in releases {
220 let mut release_elem = Element::new("Release");
221
222 let release_ref = release.release_reference.clone()
225 .unwrap_or_else(|| format!("R{}", release.release_id));
226 release_elem.add_child(
227 Element::new("ReleaseReference").with_text(&release_ref)
228 );
229
230 let mut release_id = Element::new("ReleaseId");
232 release_id.add_child(Element::new("GRid").with_text(&release.release_id));
233 release_elem.add_child(release_id);
234
235 if !release.title.is_empty() {
237 for title in &release.title {
238 let mut title_elem = Element::new("ReferenceTitle");
239 let mut title_text = Element::new("TitleText").with_text(&title.text);
240 if let Some(ref lang) = title.language_code {
241 title_text.attributes.insert("LanguageAndScriptCode".to_string(), lang.clone());
242 }
243 title_elem.add_child(title_text);
244 release_elem.add_child(title_elem);
245 }
246 }
247
248 let mut display_artist_name = Element::new("DisplayArtistName");
250 display_artist_name.add_child(Element::new("FullName").with_text(&release.artist));
251 release_elem.add_child(display_artist_name);
252
253 if let Some(ref label) = release.label {
255 let mut label_name = Element::new("LabelName");
256 label_name.add_child(Element::new("LabelName").with_text(label));
257 release_elem.add_child(label_name);
258 }
259
260 if let Some(ref upc) = release.upc {
262 let mut release_id_upc = Element::new("ReleaseId");
263 release_id_upc.add_child(Element::new("ICPN").with_text(upc));
264 release_elem.add_child(release_id_upc);
265 }
266
267 if let Some(ref release_date) = release.release_date {
269 release_elem.add_child(
270 Element::new("ReleaseDate").with_text(release_date)
271 );
272 }
273
274 if let Some(ref resource_refs) = release.resource_references {
276 for resource_ref in resource_refs {
277 release_elem.add_child(
278 Element::new("ReleaseResourceReference").with_text(resource_ref)
279 );
280 }
281 } else {
282 for track in &release.tracks {
284 let resource_ref = track.resource_reference.clone()
286 .unwrap_or_else(|| format!("A{}", track.track_id));
287 release_elem.add_child(
288 Element::new("ReleaseResourceReference").with_text(&resource_ref)
289 );
290 }
291 }
292
293 release_list.add_child(release_elem);
294 }
295
296 Ok(release_list)
297 }
298
299 fn generate_deal_list(&self, deals: &[crate::builder::DealRequest]) -> Result<Element, BuildError> {
300 let mut deal_list = Element::new("DealList");
301
302 for deal in deals {
303 let mut deal_elem = Element::new("ReleaseDeal");
304
305 if let Some(ref deal_ref) = deal.deal_reference {
307 deal_elem.add_child(Element::new("DealReference").with_text(deal_ref));
308 }
309
310 let mut deal_terms = Element::new("Deal");
312 deal_terms.add_child(
313 Element::new("CommercialModelType")
314 .with_text(&deal.deal_terms.commercial_model_type)
315 );
316
317 for territory in &deal.deal_terms.territory_code {
319 deal_terms.add_child(Element::new("TerritoryCode").with_text(territory));
320 }
321
322 deal_elem.add_child(deal_terms);
323
324 for release_ref in &deal.release_references {
326 deal_elem.add_child(
327 Element::new("DealReleaseReference").with_text(release_ref)
328 );
329 }
330
331 deal_list.add_child(deal_elem);
332 }
333
334 Ok(deal_list)
335 }
336}