From fdaf755a8a11b03642ca4809b09e04dd5e228b56 Mon Sep 17 00:00:00 2001 From: Livoroi Date: Sat, 5 Sep 2026 12:52:36 +0200 Subject: [PATCH 1/2] Add a failing test for existence with empty container values --- src/query/filter.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) 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!({ From 333eb7f456f2a99de4c300dbdf1681d27bc0f99a Mon Sep 17 00:00:00 2001 From: Livoroi Date: Sat, 5 Sep 2026 12:56:17 +0200 Subject: [PATCH 2/2] Make the existence test depend on the nodelist, not on node values --- src/query/atom.rs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) 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, };