diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b27fd68..a9bdc5e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - [623](https://github.com/thoth-pub/thoth/pull/623) - Convert connection pool errors (`r2d2::Error`) to `ThothError` + - [625](https://github.com/thoth-pub/thoth/pull/625) - Use relationcode 13 for physical ISBNs in ONIX 2.1 EBSCOHost output ## [[0.12.8]](https://github.com/thoth-pub/thoth/releases/tag/v0.12.8) - 2024-09-03 ### Fixed diff --git a/thoth-export-server/src/xml/onix21_ebsco_host.rs b/thoth-export-server/src/xml/onix21_ebsco_host.rs index bc594042..073c1bf0 100644 --- a/thoth-export-server/src/xml/onix21_ebsco_host.rs +++ b/thoth-export-server/src/xml/onix21_ebsco_host.rs @@ -108,16 +108,17 @@ impl XmlElementBlock for Work { .map_err(|e| e.into()) }) })?; - write_element_block("ProductIdentifier", w, |w| { - // 15 ISBN-13 - write_element_block("ProductIDType", w, |w| { - w.write(XmlEvent::Characters("15")).map_err(|e| e.into()) + if let Some(isbn) = &main_isbn { + write_element_block("ProductIdentifier", w, |w| { + // 15 ISBN-13 + write_element_block("ProductIDType", w, |w| { + w.write(XmlEvent::Characters("15")).map_err(|e| e.into()) + })?; + write_element_block("IDValue", w, |w| { + w.write(XmlEvent::Characters(isbn)).map_err(|e| e.into()) + }) })?; - write_element_block("IDValue", w, |w| { - w.write(XmlEvent::Characters(&main_isbn)) - .map_err(|e| e.into()) - }) - })?; + } if let Some(doi) = &self.doi { write_element_block("ProductIdentifier", w, |w| { write_element_block("ProductIDType", w, |w| { @@ -365,11 +366,16 @@ impl XmlElementBlock for Work { }) })?; if !isbns.is_empty() { - for isbn in &isbns { + for (publication_type, isbn) in &isbns { + let relation_code = match publication_type { + PublicationType::PAPERBACK | PublicationType::HARDBACK => "13", // Epublication based on (print product) + _ => "06", // Alternative format + }; + write_element_block("RelatedProduct", w, |w| { - // 06 Alternative format write_element_block("RelationCode", w, |w| { - w.write(XmlEvent::Characters("06")).map_err(|e| e.into()) + w.write(XmlEvent::Characters(relation_code)) + .map_err(|e| e.into()) })?; write_element_block("ProductIdentifier", w, |w| { // 15 ISBN-13 @@ -434,24 +440,31 @@ impl XmlElementBlock for Work { } } -fn get_publications_data(publications: &[WorkPublications]) -> (String, Vec) { - let mut main_isbn = "".to_string(); - let mut isbns: Vec = Vec::new(); +fn get_publications_data( + publications: &[WorkPublications], +) -> (Option, Vec<(PublicationType, String)>) { + let isbns: Vec<(PublicationType, String)> = publications + .iter() + .filter_map(|publication| { + publication.isbn.as_ref().map(|isbn| { + ( + publication.publication_type.clone(), + isbn.to_hyphenless_string(), + ) + }) + }) + .collect(); - for publication in publications { - if let Some(isbn) = &publication.isbn.as_ref() { - isbns.push(isbn.to_hyphenless_string()); - // The default product ISBN is the PDF's - if publication.publication_type.eq(&PublicationType::PDF) { - main_isbn = isbn.to_hyphenless_string(); - } - // Books that don't have a PDF ISBN will use the paperback's - if publication.publication_type.eq(&PublicationType::PAPERBACK) && main_isbn.is_empty() - { - main_isbn = isbn.to_hyphenless_string(); - } - } - } + // The default product ISBN is the PDF's, and fallback to a paperback if not found + let main_isbn = isbns + .iter() + .find(|(publication_type, _)| publication_type == &PublicationType::PDF) + .or_else(|| { + isbns + .iter() + .find(|(publication_type, _)| publication_type == &PublicationType::PAPERBACK) + }) + .map(|(_, isbn)| isbn.clone()); (main_isbn, isbns) } @@ -1069,6 +1082,7 @@ mod tests { assert!(output.contains(r#" WORLD"#)); assert!(output.contains(r#" "#)); assert!(output.contains(r#" 06"#)); + assert!(output.contains(r#" 13"#)); assert!(output.contains(r#" "#)); assert!(output.contains(r#" 15"#)); assert!(output.contains(r#" 9783161484100"#));