From 38c7e791f6b95d4a9d62032444d23aaea37a28d6 Mon Sep 17 00:00:00 2001 From: Ari Fogel Date: Wed, 30 Nov 2016 11:56:24 -0800 Subject: [PATCH 1/2] implement not (!) operator in filter expressions --- .../jsonpath/internal/filter/FilterCompiler.java | 15 ++++++++++++++- .../internal/filter/LogicalExpressionNode.java | 10 +++++++++- .../jsonpath/internal/filter/LogicalOperator.java | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java index 7126b278..e5eb39a3 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java @@ -120,7 +120,7 @@ public class FilterCompiler { /* * LogicalOR = LogicalAND { '||' LogicalAND } * LogicalAND = LogicalANDOperand { '&&' LogicalANDOperand } - * LogicalANDOperand = RelationalExpression | '(' LogicalOR ')' + * LogicalANDOperand = RelationalExpression | '(' LogicalOR ')' | '!' LogicalANDOperand * RelationalExpression = Value [ RelationalOperator Value ] */ @@ -164,6 +164,19 @@ public class FilterCompiler { } private ExpressionNode readLogicalANDOperand() { + int savepoint = filter.skipBlanks().position(); + if (filter.skipBlanks().currentCharIs(NOT)) { + filter.readSignificantChar(NOT); + switch (filter.skipBlanks().currentChar()) { + case DOC_CONTEXT: + case EVAL_CONTEXT: + filter.setPosition(savepoint); + break; + default: + final ExpressionNode op = readLogicalANDOperand(); + return LogicalExpressionNode.createLogicalNot(op); + } + } if (filter.skipBlanks().currentCharIs(OPEN_PARENTHESIS)) { filter.readSignificantChar(OPEN_PARENTHESIS); final ExpressionNode op = readLogicalOR(); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java index 3a5d9605..57cb3884 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java @@ -10,6 +10,10 @@ public class LogicalExpressionNode extends ExpressionNode { protected List chain = new ArrayList(); private final LogicalOperator operator; + public static ExpressionNode createLogicalNot(ExpressionNode op) { + return new LogicalExpressionNode(op, LogicalOperator.NOT, null); + } + public static LogicalExpressionNode createLogicalOr(ExpressionNode left,ExpressionNode right){ return new LogicalExpressionNode(left, LogicalOperator.OR, right); } @@ -68,13 +72,17 @@ public class LogicalExpressionNode extends ExpressionNode { } } return false; - } else { + } else if (operator == LogicalOperator.AND) { for (ExpressionNode expression : chain) { if(!expression.apply(ctx)){ return false; } } return true; + } else { + ExpressionNode expression = chain.get(0); + return !expression.apply(ctx); } } + } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalOperator.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalOperator.java index 376e2ada..809a8560 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalOperator.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalOperator.java @@ -5,6 +5,7 @@ import com.jayway.jsonpath.InvalidPathException; public enum LogicalOperator { AND("&&"), + NOT("!"), OR("||"); private final String operatorString; @@ -24,6 +25,7 @@ public enum LogicalOperator { public static LogicalOperator fromString(String operatorString){ if(AND.operatorString.equals(operatorString)) return AND; + else if(NOT.operatorString.equals(operatorString)) return NOT; else if(OR.operatorString.equals(operatorString)) return OR; else throw new InvalidPathException("Failed to parse operator " + operatorString); } From ec3a79eb77a8e260bda032d909e24b532a0d8390 Mon Sep 17 00:00:00 2001 From: Ari Fogel Date: Wed, 30 Nov 2016 12:01:34 -0800 Subject: [PATCH 2/2] updated documentation for ! filter predicate --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 50e248ca..2d5fad99 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,8 @@ List> books = JsonPath.parse(json) You can use `&&` and `||` to combine multiple predicates `[?(@.price < 10 && @.category == 'fiction')]` , `[?(@.category == 'reference' || @.price > 10)]`. +You can use `!` to negate a predicate `[?(!(@.price < 10 && @.category == 'fiction'))]`. + ###Filter Predicates Predicates can be built using the Filter API as shown below: