diff --git a/crates/preflight/src/tests.rs b/crates/preflight/src/tests.rs
index a0de793b3d..fc176e987c 100644
--- a/crates/preflight/src/tests.rs
+++ b/crates/preflight/src/tests.rs
@@ -774,6 +774,11 @@ fn xmp_value_forms_are_those_xmp_allows() {
mistyped(r#">5five"#),
["crs:Contrast"]
);
+ assert_eq!(
+ mistyped(r#">5"#),
+ ["crs:Contrast"]
+ );
+ assert!(mistyped(r#">5"#).is_empty());
// Only parseType="Resource" has a place in XMP; an rdf:resource element holds no element.
assert_eq!(mistyped(r#">5"#), ["crs:Contrast"]);
assert_eq!(mistyped(r#">"#), ["xmpMM:DerivedFrom"]);
diff --git a/crates/preflight/src/xmp_types.rs b/crates/preflight/src/xmp_types.rs
index d453ec26d1..afb1777d95 100644
--- a/crates/preflight/src/xmp_types.rs
+++ b/crates/preflight/src/xmp_types.rs
@@ -688,10 +688,10 @@ fn fits(ty: Ty, e: &Node<'_, '_>, depth: usize) -> bool {
// predefined properties keep their types too.
let node = if resource { Some(*e) } else { description };
if let Some(n) = node {
- // A qualified value has one `rdf:value`.
+ // A qualified value has one `rdf:value`: an element, or an attribute in its place.
match n.children().filter(|c| is(c, RDF, "value")).collect::>().as_slice() {
[] => {}
- [v] => return blank(e) && blank(&n) && fits(ty, v, deeper) && predefined_ok(&n, deeper),
+ [v] => return n.attribute((RDF, "value")).is_none() && blank(e) && blank(&n) && fits(ty, v, deeper) && predefined_ok(&n, deeper),
_ => return false,
}
}