json_filter 기본

This commit is contained in:
freestrings
2019-02-19 08:20:59 +09:00
parent 8d16051b80
commit 6674cb3763
10 changed files with 1198 additions and 246 deletions

772
src/jsonpath/json_filter.rs Normal file
View File

@ -0,0 +1,772 @@
use core::borrow::Borrow;
use std::cmp::Ordering;
use std::error::Error;
use std::io::Read;
use std::rc::Rc;
use std::result;
use serde_json::Value;
use serde_json::value::Index;
use jsonpath::parser::{
FilterToken,
NodeVisitor,
Parser,
ParseToken,
};
use std::collections::HashMap;
enum CmpType {
Eq,
Ne,
Gt,
Ge,
Lt,
Le,
}
trait PrivCmp {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool;
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool;
fn cmp_string(&self, v1: &String, v2: &String) -> bool;
}
trait IntoType {
fn into_type(&self) -> CmpType;
}
struct CmpEq;
impl PrivCmp for CmpEq {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
v1 == v2
}
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
v1 == v2
}
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
v1 == v2
}
}
impl IntoType for CmpEq {
fn into_type(&self) -> CmpType {
CmpType::Eq
}
}
struct CmpNe;
impl PrivCmp for CmpNe {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
v1 != v2
}
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
v1 != v2
}
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
v1 != v2
}
}
impl IntoType for CmpNe {
fn into_type(&self) -> CmpType {
CmpType::Ne
}
}
struct CmpGt;
impl PrivCmp for CmpGt {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
v1 > v2
}
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
v1 > v2
}
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
v1 > v2
}
}
impl IntoType for CmpGt {
fn into_type(&self) -> CmpType {
CmpType::Gt
}
}
struct CmpGe;
impl PrivCmp for CmpGe {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
v1 >= v2
}
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
v1 >= v2
}
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
v1 >= v2
}
}
impl IntoType for CmpGe {
fn into_type(&self) -> CmpType {
CmpType::Ge
}
}
struct CmpLt;
impl PrivCmp for CmpLt {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
v1 < v2
}
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
v1 < v2
}
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
v1 < v2
}
}
impl IntoType for CmpLt {
fn into_type(&self) -> CmpType {
CmpType::Lt
}
}
struct CmpLe;
impl PrivCmp for CmpLe {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
v1 <= v2
}
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
v1 <= v2
}
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
v1 <= v2
}
}
impl IntoType for CmpLe {
fn into_type(&self) -> CmpType {
CmpType::Le
}
}
struct CmpAnd;
impl PrivCmp for CmpAnd {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
*v1 && *v2
}
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
v1 > &0_f64 && v2 > &0_f64
}
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
!v1.is_empty() && !v2.is_empty()
}
}
struct CmpOr;
impl PrivCmp for CmpOr {
fn cmp_bool(&self, v1: &bool, v2: &bool) -> bool {
*v1 || *v2
}
fn cmp_f64(&self, v1: &f64, v2: &f64) -> bool {
v1 > &0_f64 || v2 > &0_f64
}
fn cmp_string(&self, v1: &String, v2: &String) -> bool {
!v1.is_empty() || !v2.is_empty()
}
}
#[derive(Debug)]
enum ExprTerm {
String(String),
Number(f64),
Bool(bool),
}
#[derive(Debug)]
enum TermContext {
Constants(ExprTerm),
Json(Vec<Value>),
}
impl TermContext {
fn cmp_value_term<'a, F: PrivCmp>(et: &'a ExprTerm, cmp_fn: F, default: bool)
-> impl FnMut(&&'a mut Value) -> bool {
move |v| match v {
Value::Bool(ref v1) => {
match et {
ExprTerm::Bool(v2) => cmp_fn.cmp_bool(v1, v2),
_ => default
}
}
Value::Number(ref v1) => match v1.as_f64() {
Some(ref v1) => {
match et {
ExprTerm::Number(v2) => cmp_fn.cmp_f64(v1, v2),
_ => default
}
}
_ => default
},
Value::String(ref v1) => {
match et {
ExprTerm::String(v2) => cmp_fn.cmp_string(v1, v2),
_ => default
}
}
_ => default
}
}
fn cmp_values_term<F: PrivCmp>(v: &mut Vec<Value>, et: &ExprTerm, cmp: F) -> TermContext {
let ret = v.iter_mut()
.filter(Self::cmp_value_term(et, cmp, false))
.map(|v| v.take())
.collect();
TermContext::Json(ret)
}
fn cmp_term_term<F: PrivCmp>(v1: &ExprTerm, v2: &ExprTerm, cmp_fn: F, default: bool) -> bool {
match v1 {
ExprTerm::Bool(vv1) => match v2 {
ExprTerm::Bool(vv2) => cmp_fn.cmp_bool(vv1, vv2),
_ => default
}
ExprTerm::Number(vv1) => match v2 {
ExprTerm::Number(vv2) => cmp_fn.cmp_f64(vv1, vv2),
_ => default
}
ExprTerm::String(vv1) => match v2 {
ExprTerm::String(vv2) => cmp_fn.cmp_string(vv1, vv2),
_ => default
}
}
}
fn cmp_value_value(v1: &mut Vec<Value>, v2: &mut Vec<Value>, cmp_type: CmpType) -> TermContext {
match cmp_type {
CmpType::Eq => {
let mut map: HashMap<String, Value> = HashMap::new();
for v in v1 {
map.insert(format!("{:?}", v), v.take());
}
let mut ret: HashMap<String, Value> = HashMap::new();
for v in v2 {
let key = format!("{:?}", v);
if map.contains_key(&key) {
ret.insert(key, v.take());
}
}
let v = ret.values_mut().into_iter().map(|v| v.take()).collect();
TermContext::Json(v)
}
CmpType::Ne => {
let mut map: HashMap<String, Value> = HashMap::new();
for v in v1 {
map.insert(format!("{:?}", v), v.take());
}
let mut ret: HashMap<String, Value> = HashMap::new();
for v in v2 {
let key = format!("{:?}", v);
if !map.contains_key(&key) {
ret.insert(key, v.take());
}
}
let v = ret.values_mut().into_iter().map(|v| v.take()).collect();
TermContext::Json(v)
}
CmpType::Gt | CmpType::Ge | CmpType::Lt | CmpType::Le => {
TermContext::Constants(ExprTerm::Bool(false))
}
}
}
fn cmp<F: PrivCmp + IntoType>(&mut self, other: &mut TermContext, cmp_fn: F, default: bool) -> TermContext {
match self {
TermContext::Constants(et) => {
match other {
TermContext::Constants(oet) => {
let b = Self::cmp_term_term(et, oet, cmp_fn, default);
TermContext::Constants(ExprTerm::Bool(b))
}
TermContext::Json(v) => {
Self::cmp_values_term(v, et, cmp_fn)
}
}
}
TermContext::Json(v) => {
match other {
TermContext::Json(ov) => {
Self::cmp_value_value(v, ov, cmp_fn.into_type())
}
TermContext::Constants(et) => {
Self::cmp_values_term(v, et, cmp_fn)
}
}
}
}
}
fn eq(&mut self, other: &mut TermContext) -> TermContext {
self.cmp(other, CmpEq, false)
}
fn ne(&mut self, other: &mut TermContext) -> TermContext {
self.cmp(other, CmpNe, true)
}
fn gt(&mut self, other: &mut TermContext) -> TermContext {
self.cmp(other, CmpGt, false)
}
fn ge(&mut self, other: &mut TermContext) -> TermContext {
self.cmp(other, CmpGe, false)
}
fn lt(&mut self, other: &mut TermContext) -> TermContext {
self.cmp(other, CmpLt, false)
}
fn le(&mut self, other: &mut TermContext) -> TermContext {
self.cmp(other, CmpLe, false)
}
fn cmp_cond<F: PrivCmp>(&mut self, other: &mut TermContext, cmp_fn: F) -> TermContext {
match self {
TermContext::Constants(et) => {
match other {
TermContext::Constants(oet) => {
let b = Self::cmp_term_term(et, oet, cmp_fn, false);
TermContext::Constants(ExprTerm::Bool(b))
}
TermContext::Json(v) => {
let list = v.iter_mut().map(|v| v.take()).collect();
TermContext::Json(list)
}
}
}
TermContext::Json(v) => {
match other {
TermContext::Json(ov) => {
let mut map: HashMap<String, Value> = HashMap::new();
for val in v {
map.insert(format!("{:?}", val), val.take());
}
for val in ov {
map.insert(format!("{:?}", val), val.take());
}
let list: Vec<Value> = map.values_mut().into_iter().map(|val| val.take()).collect();
TermContext::Json(list)
}
TermContext::Constants(et) => {
let list = v.iter_mut().map(|v| v.take()).collect();
TermContext::Json(list)
}
}
}
}
}
fn and(&mut self, other: &mut TermContext) -> TermContext {
self.cmp_cond(other, CmpAnd)
}
fn or(&mut self, other: &mut TermContext) -> TermContext {
self.cmp_cond(other, CmpOr)
}
}
pub struct JsonValueFilter {
json: Rc<Box<Value>>,
current: Vec<Value>,
stack: Vec<ParseToken>,
filter_stack: Vec<TermContext>,
in_array: bool,
}
impl NodeVisitor for JsonValueFilter {
fn visit_token(&mut self, token: ParseToken) {
debug!("visit_token: {:?}", token);
match token {
ParseToken::Absolute
| ParseToken::Relative
| ParseToken::In
| ParseToken::Leaves => {
self.stack.push(token);
}
ParseToken::Array => {
self.in_array = true;
}
ParseToken::ArrayEof => {
self.in_array = false;
match self.filter_stack.pop() {
Some(TermContext::Constants(_)) => unreachable!(),
Some(TermContext::Json(v)) => self.current = v,
_ => {}
}
if !self.filter_stack.is_empty() {
panic!()
}
}
ParseToken::All => {
if self.in_array {
self.stack.push(token);
} else {
match self.stack.pop() {
Some(ParseToken::In) => {
self.step_in_all();
}
Some(ParseToken::Leaves) => {
self.step_leaves_all();
}
_ => {}
}
}
}
ParseToken::Key(key) => {
if self.in_array {
self.stack.push(ParseToken::Key(key));
} else {
match self.stack.pop() {
Some(ParseToken::In) => {
self.step_in(key);
}
Some(ParseToken::Leaves) => {
self.step_leaves(key);
}
_ => {}
}
if match self.stack.last() {
Some(ParseToken::Absolute) | Some(ParseToken::Relative) => true,
_ => false
} {
self.stack.pop();
}
}
}
ParseToken::Number(_) => {
self.stack.push(token);
}
ParseToken::Filter(ref ft) => {
let left = self.filter_stack.pop();
let right = self.filter_stack.pop();
trace!("left {:?}", left);
trace!("right {:?}", right);
if let Some(mut left) = left {
if let Some(mut right) = right {
let tc = match ft {
FilterToken::Equal => left.eq(&mut right),
FilterToken::NotEqual => left.ne(&mut right),
FilterToken::Greater => left.gt(&mut right),
FilterToken::GreaterOrEqual => left.ge(&mut right),
FilterToken::Little => left.lt(&mut right),
FilterToken::LittleOrEqual => left.le(&mut right),
FilterToken::And => left.and(&mut right),
FilterToken::Or => left.or(&mut right),
};
self.filter_stack.push(tc);
}
}
}
other => {
debug!("visit_token other: {:?}", other);
}
}
}
fn clean_filter_context(&mut self) {
debug!("clean_filter_context");
self.clean_filter_path();
self.clean_filter_constants();
}
}
impl JsonValueFilter {
pub fn new(json: &str) -> result::Result<Self, String> {
let json: Value = serde_json::from_str(json)
.map_err(|e| e.description().to_string())?;
let root = json.clone();
Ok(JsonValueFilter {
json: Rc::new(Box::new(json)),
current: vec![root],
stack: Vec::new(),
filter_stack: Vec::new(),
in_array: false,
})
}
fn fork(&self, from_current: bool) -> Self {
JsonValueFilter {
json: self.json.clone(),
current: if from_current {
self.current.clone()
} else {
let v: &Value = self.json.as_ref().borrow();
vec![v.clone()]
},
stack: Vec::new(),
filter_stack: Vec::new(),
in_array: false,
}
}
fn clean_filter_path(&mut self) {
let mut paths = Vec::new();
loop {
trace!("clean_filter_path - loop: {:?}", self.stack.last());
if match self.stack.last() {
Some(ParseToken::Absolute)
| Some(ParseToken::Relative)
| Some(ParseToken::In)
| Some(ParseToken::Leaves)
| Some(ParseToken::All)
| Some(ParseToken::Key(_)) => true,
_ => false
} {
self.stack.pop().map(|t| paths.push(t));
} else {
break;
}
}
trace!("clean_filter_path: {:?}", paths);
if let Some(forked) = match paths.pop() {
Some(ParseToken::Absolute) => {
Some(self.fork(false))
}
Some(ParseToken::Relative) => {
Some(self.fork(true))
}
_ => None
}.and_then(|mut forked| {
while let Some(t) = paths.pop() {
forked.visit_token(t);
}
Some(forked)
}) {
trace!("clean_filter_path -> {:?}", forked.current);
self.filter_stack.push(TermContext::Json(forked.current));
}
}
fn clean_filter_constants(&mut self) {
trace!("clean_filter_constants: {:?}", self.stack.last());
if match self.stack.last() {
Some(ParseToken::Key(_))
| Some(ParseToken::Number(_)) => true,
_ => false
} {
match self.stack.pop() {
Some(ParseToken::Key(ref v)) if v.eq_ignore_ascii_case("true") => {
self.filter_stack.push(TermContext::Constants(ExprTerm::Bool(true)))
}
Some(ParseToken::Key(ref v)) if v.eq_ignore_ascii_case("false") => {
self.filter_stack.push(TermContext::Constants(ExprTerm::Bool(false)))
}
Some(ParseToken::Key(v)) => {
self.filter_stack.push(TermContext::Constants(ExprTerm::String(v)))
}
Some(ParseToken::Number(v)) => {
self.filter_stack.push(TermContext::Constants(ExprTerm::Number(v)))
}
_ => {}
}
}
}
fn step_leaves_all(&mut self) -> &Vec<Value> {
debug!("step_leaves_all");
let mut buf = Vec::new();
loop {
self.step_in_all().iter().map(|v| buf.push(v.clone()));
if self.current.len() == 0 {
break;
}
}
self.current = buf;
&self.current
}
fn step_leaves(&mut self, key: String) -> &Vec<Value> {
debug!("step_leaves");
let mut buf = Vec::new();
loop {
self.step_in(key.clone()).iter().map(|v| buf.push(v.clone()));
if self.current.len() == 0 {
break;
}
}
self.current = buf;
&self.current
}
fn step_in_all(&mut self) -> &Vec<Value> {
debug!("step_in_all");
fn to_vec<'a, I: Iterator<Item=&'a mut Value>>(iter: I) -> Vec<Value> {
iter.map(|v| v.take())
.filter(|v| !v.is_null())
.collect()
}
self.current = self.current.iter_mut()
.flat_map(|v| {
match v {
Value::Object(map) => to_vec(map.values_mut()),
Value::Array(list) => to_vec(list.iter_mut()),
Value::Null => Vec::new(),
_ => vec![v.take()]
}
}).collect();
&self.current
}
fn step_in<I: Index>(&mut self, key: I) -> &Vec<Value> {
debug!("step_in");
self.current = self.current.iter_mut()
.map(|v| {
trace!("step_in - map: {:?}", v);
match v.get_mut(&key) {
Some(value) => value.take(),
_ => Value::Null
}
})
.filter(|v| !v.is_null())
.collect();
&self.current
}
fn current(&self) -> &Vec<Value> {
&self.current
}
}
#[cfg(test)]
mod tests {
extern crate env_logger;
use std::sync::{Once, ONCE_INIT};
use jsonpath::tokenizer::PreloadedTokenizer;
use super::*;
static INIT: Once = ONCE_INIT;
fn setup() {
INIT.call_once(|| {
env_logger::init();
});
}
fn read_json(path: &str) -> String {
let mut f = std::fs::File::open(path).unwrap();
let mut contents = String::new();
f.read_to_string(&mut contents).unwrap();
contents
}
#[test]
fn step_in() {
setup();
let string = read_json("./benches/data_obj.json");
let mut jf = JsonValueFilter::new(string.as_str()).unwrap();
{
let current = jf.step_in("friends");
assert_eq!(current[0].is_array(), true);
}
let string = read_json("./benches/data_array.json");
let mut jf = JsonValueFilter::new(string.as_str()).unwrap();
{
let current = jf.step_in(1);
assert_eq!(current[0].is_object(), true);
}
{
let current = jf.step_in("friends");
assert_eq!(current[0].is_array(), true);
}
}
#[test]
fn fork() {
setup();
let string = read_json("./benches/data_obj.json");
let mut jf = JsonValueFilter::new(string.as_str()).unwrap();
{
let current = jf.step_in("friends");
assert_eq!(current[0].is_array(), true);
}
let jf_from_current = jf.fork(true);
{
let current = jf_from_current.current();
assert_eq!(current[0].is_array(), true);
}
let mut jf_from_root = jf_from_current.fork(false);
{
let current = jf_from_root.step_in("age");
assert_eq!(current[0].is_number(), true);
}
}
#[test]
fn filter() {
setup();
let string = read_json("./benches/data_obj.json");
let mut jf = JsonValueFilter::new(string.as_str()).unwrap();
let mut parser = Parser::new("$.school[?(@.friends==@.friends)]");
parser.parse(&mut jf).unwrap();
let v = json!([
{"id": 0,"name": "Millicent Norman"},
{"id": 1,"name": "Vincent Cannon" },
{"id": 2,"name": "Gray Berry"}
]);
assert_eq!(v, jf.current());
}
}

View File

@ -1,27 +1,12 @@
pub mod path_reader;
pub mod tokenizer;
pub mod parser;
mod path_reader;
mod tokenizer;
mod parser;
mod json_filter;
mod utils;
mod utils {
use std::result;
use std::result;
pub fn vec_to_int<F>(vec: &Vec<char>, msg_handler: F) -> result::Result<isize, String>
where F: Fn() -> String {
match vec.iter().map(|c| *c).collect::<String>().as_str().parse::<isize>() {
Ok(n) => Ok(n),
_ => Err(msg_handler())
}
}
fn read(json: &str, path: &str) -> result::Result<(), String> {
pub fn vec_to_float<F>(vec: &Vec<char>, msg_handler: F) -> result::Result<f64, String>
where F: Fn() -> String {
match vec.iter().map(|c| *c).collect::<String>().as_str().parse::<f64>() {
Ok(n) => Ok(n),
_ => Err(msg_handler())
}
}
pub fn vec_to_string(vec: &Vec<char>) -> String {
vec.iter().map(|c| *c).collect::<String>()
}
Ok(())
}

View File

@ -1,7 +1,6 @@
use std::result;
use super::tokenizer::{
self,
Token,
PreloadedTokenizer,
TokenError,
@ -13,7 +12,7 @@ const DUMMY: usize = 0;
type Result<T> = result::Result<T, String>;
#[derive(Debug, PartialEq)]
enum ParseToken {
pub enum ParseToken {
// '$'
Absolute,
// '@'
@ -43,33 +42,37 @@ enum ParseToken {
}
#[derive(Debug, PartialEq)]
enum FilterToken {
pub enum FilterToken {
Equal,
NotEqual,
Little,
LittleOrEqual,
Greater,
GreaterOrEqual,
Literal(String),
Number(f64),
And,
Or,
}
#[derive(Debug)]
struct Node {
pub struct Node {
left: Option<Box<Node>>,
right: Option<Box<Node>>,
token: ParseToken,
}
struct Parser<'a> {
pub struct Parser<'a> {
tokenizer: PreloadedTokenizer<'a>
}
impl<'a> Parser<'a> {
fn parse(&mut self) -> Result<Node> {
self.json_path()
pub fn new(input: &'a str) -> Self {
Parser { tokenizer: PreloadedTokenizer::new(input) }
}
pub fn parse<V: NodeVisitor>(&mut self, visitor: &mut V) -> Result<()> {
let node = self.json_path()?;
visitor.visit(node);
Ok(())
}
fn json_path(&mut self) -> Result<Node> {
@ -85,7 +88,7 @@ impl<'a> Parser<'a> {
}
}
fn paths(&mut self, mut prev: Node) -> Result<Node> {
fn paths(&mut self, prev: Node) -> Result<Node> {
debug!("#paths");
match self.tokenizer.peek_token() {
Ok(Token::Dot(_)) => {
@ -441,9 +444,30 @@ impl<'a> Parser<'a> {
fn expr(&mut self) -> Result<Node> {
debug!("#expr");
let has_prop_candidate = match self.tokenizer.peek_token() {
Ok(Token::At(_)) => true,
_ => false
};
let node = self.term()?;
self.eat_whitespace();
self.op(node)
if match self.tokenizer.peek_token() {
Ok(Token::Equal(_))
| Ok(Token::NotEqual(_))
| Ok(Token::Little(_))
| Ok(Token::LittleOrEqual(_))
| Ok(Token::Greater(_))
| Ok(Token::GreaterOrEqual(_)) => true,
_ => false
} {
self.op(node)
} else if has_prop_candidate {
Ok(node)
} else {
return Err(self.tokenizer.err_msg());
}
}
fn term_num(&mut self) -> Result<Node> {
@ -574,7 +598,7 @@ impl<'a> Parser<'a> {
Node { left: None, right: None, token: token }
}
fn close_token(&mut self, mut ret: Node, token: Token) -> Result<Node> {
fn close_token(&mut self, ret: Node, token: Token) -> Result<Node> {
debug!("#close_token");
match self.tokenizer.next_token() {
Ok(ref t) if t.partial_eq(token) => {
@ -583,158 +607,59 @@ impl<'a> Parser<'a> {
Err(TokenError::Eof) => {
Ok(ret)
}
other => {
_ => {
Err(self.tokenizer.err_msg())
}
}
}
}
trait NodeVisitor {
fn visit(&mut self, node: Node);
}
#[derive(Debug)]
enum InterpreterToken {
Path(Vec<ParseToken>, ParseToken),
Token(ParseToken),
}
struct Interpreter<'a> {
input: &'a str,
stack: Vec<Vec<ParseToken>>,
}
impl<'a> Interpreter<'a> {
fn new(input: &'a str) -> Self {
Interpreter { input, stack: vec![] }
}
fn interpret(&mut self) -> result::Result<Vec<Vec<ParseToken>>, String> {
let tokenizer = PreloadedTokenizer::new(self.input);
let mut parser = Parser { tokenizer };
let node = parser.parse()?;
self.visit(node);
self.flush_path();
self.flush_meta();
Ok(self.stack.split_off(0))
}
fn flush_path(&mut self) {
let mut buf = vec![];
loop {
if !match self.stack.last() {
Some(n) if n.len() == 1 => {
match n[0] {
ParseToken::Absolute
| ParseToken::Relative
| ParseToken::In
| ParseToken::Leaves
| ParseToken::All
| ParseToken::Key(_) => true,
_ => false
}
}
_ => false
} {
break;
}
self.stack.pop().map(|mut e| buf.insert(0, e.pop().unwrap()));
}
if buf.len() > 0 {
self.flush_meta();
self.stack.push(buf);
}
}
fn flush_expr(&mut self) {
if match self.stack.last() {
Some(n) if n.len() == 1 => {
match n[0] {
ParseToken::Filter(FilterToken::Equal)
| ParseToken::Filter(FilterToken::NotEqual)
| ParseToken::Filter(FilterToken::Little)
| ParseToken::Filter(FilterToken::LittleOrEqual)
| ParseToken::Filter(FilterToken::Greater)
| ParseToken::Filter(FilterToken::GreaterOrEqual) => true,
_ => false
}
}
_ => false
} {
let mut op = self.stack.pop().unwrap();
let mut term = self.stack.pop().unwrap();
self.stack.last_mut().map(|v| {
v.append(&mut op);
v.append(&mut term);
});
}
}
fn flush_meta(&mut self) {
if match self.stack.last() {
Some(t) if t.len() == 1 => {
match t.last() {
Some(ParseToken::ArrayEof) => true,
_ => false
}
}
_ => false
} {
self.stack.pop();
}
}
}
impl<'a> NodeVisitor for Interpreter<'a> {
pub trait NodeVisitor {
fn visit(&mut self, node: Node) {
match node.token {
ParseToken::Absolute
| ParseToken::Relative
| ParseToken::All
| ParseToken::Key(_) => {
self.stack.push(vec![node.token]);
self.visit_token(node.token);
}
ParseToken::In
| ParseToken::Leaves => {
node.left.map(|n| self.visit(*n));
self.stack.push(vec![node.token]);
self.visit_token(node.token);
node.right.map(|n| self.visit(*n));
}
| ParseToken::Range(_, _)
| ParseToken::Union(_)
| ParseToken::Number(_) => {
self.stack.push(vec![node.token]);
self.visit_token(node.token);
}
| ParseToken::Array => {
node.left.map(|n| self.visit(*n));
self.flush_path();
self.flush_meta();
self.stack.push(vec![node.token]);
self.visit_token(node.token);
node.right.map(|n| self.visit(*n));
self.stack.push(vec![ParseToken::ArrayEof]);
self.visit_token(ParseToken::ArrayEof);
}
ParseToken::Filter(FilterToken::And)
| ParseToken::Filter(FilterToken::Or) => {
node.left.map(|n| self.visit(*n));
node.right.map(|n| self.visit(*n));
self.stack.push(vec![node.token]);
self.visit_token(node.token);
}
ParseToken::Filter(_) => {
node.left.map(|n| self.visit(*n));
self.flush_path();
self.clean_filter_context();
node.right.map(|n| self.visit(*n));
self.flush_path();
self.stack.push(vec![node.token]);
self.flush_expr();
self.clean_filter_context();
self.visit_token(node.token);
}
_ => {}
}
}
fn visit_token(&mut self, token: ParseToken);
fn clean_filter_context(&mut self) {}
}
#[cfg(test)]
@ -747,15 +672,39 @@ mod tests {
static INIT: Once = ONCE_INIT;
struct NodeVisitorTestImpl<'a> {
input: &'a str,
stack: Vec<ParseToken>,
}
impl<'a> NodeVisitorTestImpl<'a> {
fn new(input: &'a str) -> Self {
NodeVisitorTestImpl { input, stack: Vec::new() }
}
fn visit(&mut self) -> result::Result<Vec<ParseToken>, String> {
let tokenizer = PreloadedTokenizer::new(self.input);
let mut parser = Parser { tokenizer };
parser.parse(self)?;
Ok(self.stack.split_off(0))
}
}
impl<'a> NodeVisitor for NodeVisitorTestImpl<'a> {
fn visit_token(&mut self, token: ParseToken) {
self.stack.push(token);
}
}
fn setup() {
INIT.call_once(|| {
env_logger::init();
});
}
fn run(input: &str) -> result::Result<Vec<Vec<ParseToken>>, String> {
let mut interpreter = Interpreter::new(input);
interpreter.interpret()
fn run(input: &str) -> result::Result<Vec<ParseToken>, String> {
let mut interpreter = NodeVisitorTestImpl::new(input);
interpreter.visit()
}
#[test]
@ -763,44 +712,39 @@ mod tests {
setup();
assert_eq!(run("$.aa"), Ok(vec![
vec![ParseToken::Absolute,
ParseToken::In,
ParseToken::Key("aa".to_owned())
]
ParseToken::Absolute,
ParseToken::In,
ParseToken::Key("aa".to_owned())
]));
assert_eq!(run("$.00.a"), Ok(vec![
vec![ParseToken::Absolute,
ParseToken::In,
ParseToken::Key("00".to_owned()),
ParseToken::In,
ParseToken::Key("a".to_owned())
]
ParseToken::Absolute,
ParseToken::In,
ParseToken::Key("00".to_owned()),
ParseToken::In,
ParseToken::Key("a".to_owned())
]));
assert_eq!(run("$.00.韓창.seok"), Ok(vec![
vec![ParseToken::Absolute,
ParseToken::In,
ParseToken::Key("00".to_owned()),
ParseToken::In,
ParseToken::Key("韓창".to_owned()),
ParseToken::In,
ParseToken::Key("seok".to_owned())
]
ParseToken::Absolute,
ParseToken::In,
ParseToken::Key("00".to_owned()),
ParseToken::In,
ParseToken::Key("韓창".to_owned()),
ParseToken::In,
ParseToken::Key("seok".to_owned())
]));
assert_eq!(run("$.*"), Ok(vec![
vec![ParseToken::Absolute,
ParseToken::In,
ParseToken::All
]
ParseToken::Absolute,
ParseToken::In,
ParseToken::All
]));
assert_eq!(run("$..*"), Ok(vec![
vec![ParseToken::Absolute,
ParseToken::Leaves,
ParseToken::All
]
ParseToken::Absolute,
ParseToken::Leaves,
ParseToken::All
]));
match run("$.") {
@ -823,110 +767,148 @@ mod tests {
fn parse_array() {
setup();
assert_eq!(run("$.book[?(@.isbn)]"), Ok(vec![
ParseToken::Absolute,
ParseToken::In,
ParseToken::Key("book".to_string()),
ParseToken::Array,
ParseToken::Relative,
ParseToken::In,
ParseToken::Key("isbn".to_string()),
ParseToken::ArrayEof
]));
//
// Array도 컨텍스트 In으로 간주 할거라서 중첩되면 하나만
//
assert_eq!(run("$.[*]"), Ok(vec![
vec![ParseToken::Absolute],
vec![ParseToken::Array],
vec![ParseToken::All]
ParseToken::Absolute,
ParseToken::Array,
ParseToken::All,
ParseToken::ArrayEof
]));
assert_eq!(run("$.a[*]"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::All]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::All,
ParseToken::ArrayEof
]));
assert_eq!(run("$.a[*].가"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::All],
vec![ParseToken::In, ParseToken::Key("".to_owned())]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::All,
ParseToken::ArrayEof,
ParseToken::In, ParseToken::Key("".to_owned())
]));
assert_eq!(run("$.a[0][1]"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::Number(0_f64)],
vec![ParseToken::Array],
vec![ParseToken::Number(1_f64)]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::Number(0_f64),
ParseToken::ArrayEof,
ParseToken::Array,
ParseToken::Number(1_f64),
ParseToken::ArrayEof
]));
assert_eq!(run("$.a[1,2]"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::Union(vec![1, 2])]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::Union(vec![1, 2]),
ParseToken::ArrayEof
]));
assert_eq!(run("$.a[10:]"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::Range(Some(10), None)]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::Range(Some(10), None),
ParseToken::ArrayEof
]));
assert_eq!(run("$.a[:11]"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::Range(None, Some(11))]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::Range(None, Some(11)),
ParseToken::ArrayEof
]));
assert_eq!(run("$.a[-12:13]"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::Range(Some(-12), Some(13))]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::Range(Some(-12), Some(13)),
ParseToken::ArrayEof
]));
assert_eq!(run("$.a[?(1>2)]"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::Number(1_f64), ParseToken::Filter(FilterToken::Greater), ParseToken::Number(2_f64)]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Greater),
ParseToken::ArrayEof
]));
assert_eq!(run("$.a[?($.b>3)]"), Ok(vec![
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned())],
vec![ParseToken::Array],
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("b".to_owned()), ParseToken::Filter(FilterToken::Greater), ParseToken::Number(3_f64)]
ParseToken::Absolute, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Array,
ParseToken::Absolute, ParseToken::In, ParseToken::Key("b".to_owned()), ParseToken::Number(3_f64), ParseToken::Filter(FilterToken::Greater),
ParseToken::ArrayEof
]));
assert_eq!(run("$[?($.c>@.d && 1==2)]"), Ok(vec![
vec![ParseToken::Absolute],
vec![ParseToken::Array],
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()),
ParseToken::Filter(FilterToken::Greater),
ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned())],
vec![ParseToken::Number(1_f64), ParseToken::Filter(FilterToken::Equal), ParseToken::Number(2_f64)],
vec![ParseToken::Filter(FilterToken::And)]
ParseToken::Absolute,
ParseToken::Array,
ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()),
ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()),
ParseToken::Filter(FilterToken::Greater),
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal),
ParseToken::Filter(FilterToken::And),
ParseToken::ArrayEof
]));
assert_eq!(run("$[?($.c>@.d&&(1==2||3>=4))]"), Ok(vec![
vec![ParseToken::Absolute],
vec![ParseToken::Array],
vec![ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()),
ParseToken::Filter(FilterToken::Greater),
ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned())],
vec![ParseToken::Number(1_f64), ParseToken::Filter(FilterToken::Equal), ParseToken::Number(2_f64)],
vec![ParseToken::Number(3_f64), ParseToken::Filter(FilterToken::GreaterOrEqual), ParseToken::Number(4_f64)],
vec![ParseToken::Filter(FilterToken::Or)],
vec![ParseToken::Filter(FilterToken::And)]
ParseToken::Absolute,
ParseToken::Array,
ParseToken::Absolute, ParseToken::In, ParseToken::Key("c".to_owned()),
ParseToken::Relative, ParseToken::In, ParseToken::Key("d".to_owned()),
ParseToken::Filter(FilterToken::Greater),
ParseToken::Number(1_f64), ParseToken::Number(2_f64), ParseToken::Filter(FilterToken::Equal),
ParseToken::Number(3_f64), ParseToken::Number(4_f64), ParseToken::Filter(FilterToken::GreaterOrEqual),
ParseToken::Filter(FilterToken::Or),
ParseToken::Filter(FilterToken::And),
ParseToken::ArrayEof
]));
assert_eq!(run("$[?(@.a<@.b)]"), Ok(vec![
vec![ParseToken::Absolute],
vec![ParseToken::Array],
vec![ParseToken::Relative, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Filter(FilterToken::Little),
ParseToken::Relative, ParseToken::In, ParseToken::Key("b".to_owned())]
ParseToken::Absolute,
ParseToken::Array,
ParseToken::Relative, ParseToken::In, ParseToken::Key("a".to_owned()),
ParseToken::Relative, ParseToken::In, ParseToken::Key("b".to_owned()),
ParseToken::Filter(FilterToken::Little),
ParseToken::ArrayEof
]));
assert_eq!(run("$[*][*][*]"), Ok(vec![
vec![ParseToken::Absolute],
vec![ParseToken::Array],
vec![ParseToken::All],
vec![ParseToken::Array],
vec![ParseToken::All],
vec![ParseToken::Array],
vec![ParseToken::All]
ParseToken::Absolute,
ParseToken::Array,
ParseToken::All,
ParseToken::ArrayEof,
ParseToken::Array,
ParseToken::All,
ParseToken::ArrayEof,
ParseToken::Array,
ParseToken::All,
ParseToken::ArrayEof
]));
assert_eq!(run("$['a']['bb']"), Ok(vec![
ParseToken::Absolute,
ParseToken::Array,
ParseToken::Key("a".to_string()),
ParseToken::ArrayEof,
ParseToken::Array,
ParseToken::Key("bb".to_string()),
ParseToken::ArrayEof
]));
match run("$[]") {
@ -960,9 +942,10 @@ mod tests {
setup();
assert_eq!(run("$[?(1.1<2.1)]"), Ok(vec![
vec![ParseToken::Absolute],
vec![ParseToken::Array],
vec![ParseToken::Number(1.1), ParseToken::Filter(FilterToken::Little), ParseToken::Number(2.1)]
ParseToken::Absolute,
ParseToken::Array,
ParseToken::Number(1.1), ParseToken::Number(2.1), ParseToken::Filter(FilterToken::Little),
ParseToken::ArrayEof
]));
match run("$[1.1]") {

View File

@ -6,8 +6,6 @@ use jsonpath::path_reader::{
PathReader,
};
use super::utils;
const ABSOLUTE: &'static str = "$";
const DOT: &'static str = ".";
const AT: &'static str = "@";
@ -31,7 +29,6 @@ const NOT_EQUAL: &'static str = "!=";
const AND: &'static str = "&&";
const OR: &'static str = "||";
const WHITESPACE: &'static str = " ";
const EOF: &'static str = "Eof";
const CH_DOLLA: char = '$';
const CH_DOT: char = '.';
@ -146,14 +143,12 @@ fn simple_matched_token(ch: char, pos: usize) -> Option<Token> {
pub struct Tokenizer<'a> {
input: PathReader<'a>,
token_list: Vec<Token>,
}
impl<'a> Tokenizer<'a> {
pub fn new(input: &'a str) -> Self {
Tokenizer {
input: PathReader::new(input),
token_list: Vec::new(),
}
}

21
src/jsonpath/utils.rs Normal file
View File

@ -0,0 +1,21 @@
use std::result;
pub fn vec_to_int<F>(vec: &Vec<char>, msg_handler: F) -> result::Result<isize, String>
where F: Fn() -> String {
match vec.iter().map(|c| *c).collect::<String>().as_str().parse::<isize>() {
Ok(n) => Ok(n),
_ => Err(msg_handler())
}
}
pub fn vec_to_float<F>(vec: &Vec<char>, msg_handler: F) -> result::Result<f64, String>
where F: Fn() -> String {
match vec.iter().map(|c| *c).collect::<String>().as_str().parse::<f64>() {
Ok(n) => Ok(n),
_ => Err(msg_handler())
}
}
pub fn vec_to_string(vec: &Vec<char>) -> String {
vec.iter().map(|c| *c).collect::<String>()
}

View File

@ -2,6 +2,8 @@
extern crate log;
extern crate env_logger;
extern crate serde;
#[macro_use]
extern crate serde_json;
extern crate core;
pub mod jsonpath;