diff --git a/src/query/atom.rs b/src/query/atom.rs index f51b03e..29e33e3 100644 --- a/src/query/atom.rs +++ b/src/query/atom.rs @@ -24,22 +24,12 @@ impl Query for FilterAtom { res } } else { - let struct_check = |s: &T| { - if let Some(arr) = s.as_array() { - !arr.is_empty() - } else if let Some(obj) = s.as_object() { - !obj.is_empty() - } else if let Some(str) = s.as_str() { - !str.is_empty() - } else { - true - } - }; - + // RFC 9535 2.3.5.2: a test expression is true when the + // nodelist it produces is non-empty. The value of the nodes + // does not take part in the decision. let struct_presented = match res.data { - Data::Ref(v) => struct_check(v.inner), - Data::Refs(e) if e.is_empty() => false, - Data::Refs(elems) => elems.iter().map(|v| v.inner).all(struct_check), + Data::Ref(_) => true, + Data::Refs(elems) => !elems.is_empty(), _ => false, }; diff --git a/src/query/filter.rs b/src/query/filter.rs index bfa0721..8554270 100644 --- a/src/query/filter.rs +++ b/src/query/filter.rs @@ -97,6 +97,28 @@ mod tests { ); } + #[test] + fn existence_of_empty_containers() { + let json = json!({ + "a": { + "empty_array": {"b": []}, + "empty_object": {"b": {}}, + "empty_string": {"b": ""}, + "no_b": {"c": 1} + } + }); + // RFC 9535 2.3.5.2: a test expression is true when the nodelist it + // produces is non-empty, whatever the value of the nodes. + assert_eq!( + js_path("$.a[?@.b]", &json), + Ok(vec![ + (&json!({"b": []}), "$['a']['empty_array']".to_string()).into(), + (&json!({"b": {}}), "$['a']['empty_object']".to_string()).into(), + (&json!({"b": ""}), "$['a']['empty_string']".to_string()).into(), + ]) + ); + } + #[test] fn existence_or() { let json = json!({