diff --git a/.idea/runConfigurations/filter_array____trace.xml b/.idea/runConfigurations/filter_array____trace.xml new file mode 100644 index 0000000..f327ca8 --- /dev/null +++ b/.idea/runConfigurations/filter_array____trace.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/src/jsonpath/json_filter/mod.rs b/src/jsonpath/json_filter/mod.rs index b882466..5d8ca5f 100644 --- a/src/jsonpath/json_filter/mod.rs +++ b/src/jsonpath/json_filter/mod.rs @@ -112,6 +112,22 @@ mod tests { {"id": 0, "name": "Millicent Norman"} ]); assert_eq!(&friends, jf.current_value()); + + let jf = do_filter("$..friends[2].name", "./benches/data_obj.json"); + let friends = json!(["Gray Berry", "Gray Berry"]); + assert_eq!(&friends, jf.current_value()); + + let jf = do_filter("$..friends[*].name", "./benches/data_obj.json"); + let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]); + assert_eq!(&friends, jf.current_value()); + + let jf = do_filter("$['school']['friends'][*].['name']", "./benches/data_obj.json"); + let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]); + assert_eq!(&friends, jf.current_value()); + + let jf = do_filter("$['school']['friends'][0].['name']", "./benches/data_obj.json"); + let friends = json!("Millicent Norman"); + assert_eq!(&friends, jf.current_value()); } #[test] diff --git a/src/jsonpath/json_filter/value_filter.rs b/src/jsonpath/json_filter/value_filter.rs index 2f7ba03..df3a404 100644 --- a/src/jsonpath/json_filter/value_filter.rs +++ b/src/jsonpath/json_filter/value_filter.rs @@ -169,7 +169,7 @@ impl ValueFilter { pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper { debug!("step_in_num"); - trace!("step_in_num - before: {} - {:?}", self.filter_mode, self.vw.get_val()); + trace!("step_in_num - before: leaves {}, filterMode {} - {:?}", self.vw.is_leaves(), self.filter_mode, self.vw.get_val()); let v = if self.vw.is_leaves() { let filter_mode = self.filter_mode; @@ -213,6 +213,11 @@ impl ValueFilter { .filter(|v| !v.is_null()) .collect(); buf.append(&mut ret); + } else { + match item.get_mut(key) { + Some(v) => buf.push(v.take()), + _ => {} + } } } @@ -294,12 +299,13 @@ impl JsonValueFilter { } } - fn replace_filter_stack(&mut self, v: Value) { + fn replace_filter_stack(&mut self, v: Value, is_leaves: bool) { if self.filter_stack.is_empty() { - self.filter_stack.push(ValueFilter::new(v, false, false)); + self.filter_stack.push(ValueFilter::new(v, is_leaves, false)); } else { match self.filter_stack.last_mut() { Some(vf) => { + vf.vw.set_leaves(is_leaves); if v.is_null() { vf.vw.replace(v); } else if vf.vw.is_array() { @@ -403,7 +409,7 @@ impl JsonValueFilter { match self.filter_stack.last_mut() { Some(vf) => { match self.token_stack.pop() { - Some(ParseToken::In) => { + Some(ParseToken::In) | Some(ParseToken::Array) => { vf.step_in_string(&key); } Some(ParseToken::Leaves) => { @@ -447,17 +453,18 @@ impl JsonValueFilter { } } Some(TermContext::Json(_, mut vw)) => { - self.replace_filter_stack(vw.get_val_mut().take()); + self.replace_filter_stack(vw.get_val_mut().take(), vw.is_leaves()); } _ => { match self.filter_stack.pop() { Some(mut vf) => { + let is_leaves = vf.vw.is_leaves(); match vf.vw.get_val_mut() { Value::Null | Value::Bool(false) => { - self.replace_filter_stack(Value::Null); + self.replace_filter_stack(Value::Null, is_leaves); } other => { - self.replace_filter_stack(other.take()); + self.replace_filter_stack(other.take(), is_leaves); } } } diff --git a/src/jsonpath/json_filter/value_wrapper.rs b/src/jsonpath/json_filter/value_wrapper.rs index 8ca8964..6291d16 100644 --- a/src/jsonpath/json_filter/value_wrapper.rs +++ b/src/jsonpath/json_filter/value_wrapper.rs @@ -8,16 +8,20 @@ use super::value_filter::*; #[derive(Debug)] pub struct ValueWrapper { val: Value, - leaves: bool, + is_leaves: bool, } impl ValueWrapper { pub fn new(val: Value, leaves: bool) -> Self { - ValueWrapper { val, leaves } + ValueWrapper { val, is_leaves: leaves } } pub fn is_leaves(&self) -> bool { - self.leaves + self.is_leaves + } + + pub fn set_leaves(&mut self, is_leaves: bool) { + self.is_leaves = is_leaves; } pub fn cmp(&mut self, other: &mut ValueWrapper, cmp_type: CmpType) -> TermContext { diff --git a/src/jsonpath/parser.rs b/src/jsonpath/parser.rs index 031a000..955dd29 100644 --- a/src/jsonpath/parser.rs +++ b/src/jsonpath/parser.rs @@ -183,6 +183,11 @@ impl<'a> Parser<'a> { Ok(Token::Asterisk(_)) => { self.path_leaves_all(prev) } + Ok(Token::OpenArray(_)) => { + let mut leaves_node = self.node(ParseToken::Leaves); + leaves_node.left = Some(Box::new(prev)); + Ok(self.paths(leaves_node)?) + } _ => { self.path_leaves_key(prev) } @@ -774,6 +779,14 @@ mod tests { ParseToken::All ])); + assert_eq!(run("$..[0]"), Ok(vec![ + ParseToken::Absolute, + ParseToken::Leaves, + ParseToken::Array, + ParseToken::Number(0.0), + ParseToken::ArrayEof + ])); + match run("$.") { Ok(_) => panic!(), _ => {}