diff --git a/crates/organize/src/xmp.rs b/crates/organize/src/xmp.rs index 21cb282c21..9ed9c3320c 100644 --- a/crates/organize/src/xmp.rs +++ b/crates/organize/src/xmp.rs @@ -119,12 +119,13 @@ fn get_property(xmp: &str, name: &str, shape: Shape) -> Option { let inner = element.get(open_end + 1..)?.strip_suffix(&format!(""))?; let items = list_items(inner); if items.is_empty() { - unescape(inner.trim()) + // An empty `` or `` has no value, not its markup. + text_value(inner)? } else if shape == Shape::LangAlt { let (_, text) = items.iter().find(|(lang, _)| lang.as_deref() == Some("x-default")).or(items.first())?; - unescape(text.trim()) + text_value(text)? } else { - items.iter().map(|(_, text)| unescape(text.trim())).filter(|t| !t.is_empty()).collect::>().join("; ") + items.iter().filter_map(|(_, text)| text_value(text)).filter(|t| !t.is_empty()).collect::>().join("; ") } } else { let (_, value_start, value_end, _) = attribute_span(xmp, name)?; @@ -133,6 +134,13 @@ fn get_property(xmp: &str, name: &str, shape: Shape) -> Option { Some(value).filter(|v| !v.trim().is_empty()) } +/// Character data `text` as a value, unescaped; `None` when it still holds markup (a `<`, which +/// a value escapes as `<`), so a structure the reader doesn't take apart never shows as text. +fn text_value(text: &str) -> Option { + let text = text.trim(); + (!text.contains('<')).then(|| unescape(text)) +} + /// The `rdf:li` items of a property's content: each one's `xml:lang` (if any) and its text. fn list_items(inner: &str) -> Vec<(Option, &str)> { let mut items = Vec::new(); @@ -334,6 +342,12 @@ mod tests { assert_eq!(get_property(seq, "dc:creator", Shape::Seq).as_deref(), Some("Ada")); // Unfinished markup reads as nothing rather than as a wrong value. assert_eq!(get_property("Cut", "dc:title", Shape::LangAlt), None); + // An empty alternative or list, or an item holding markup, has no value: never the markup. + assert_eq!(get_property("", "dc:title", Shape::LangAlt), None); + assert_eq!(get_property("", "dc:title", Shape::LangAlt), None); + assert_eq!(get_property("", "dc:creator", Shape::Seq), None); + let nested = "Ada"; + assert_eq!(get_property(nested, "dc:creator", Shape::Seq).as_deref(), Some("Ada")); } #[test]