检查 JSONObject 是否与 JSON 布尔表达式匹配



为了正确解释这个问题,我必须从一个例子开始,假设我有一个这样的用户列表

[
{ "name": "John",  "surname": "Doe",   "age": 22 },
{ "name": "Syrus", "surname": "Black", "age": 20 }
]

我还有一个JSONObject表示必须像这样匹配的条件:

{
"OR":[
{ "name": { "eq": "John"} },
{ "AND":[
{ "name": { "eq": "Syrus"} },
{ "age": { "gt": 18 } }
] }
]
}

应该翻译成:

name = "John" OR (name = "Syrus" AND age > 18)

现在,我必须使给定JSONObject条件的代码和用户列表检查每个用户的条件是否匹配。 目前,这就是我所做的:

import java.util.Set;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiConsumer;
import com.query.Queryable;
import org.json.JSONArray;
import org.json.JSONObject;
public class QueryableTreeMap<K,V extends JSONObject> extends TreeMap<K,V> implements Queryable<JSONObject,JSONObject> {
private static final long serialVersionUID = 2586026774025401270L;
private static boolean test(Set<Map.Entry<String, Object>> condition, JSONObject value){
boolean isValid = true;
Iterator<Map.Entry<String, Object>> iter = condition.iterator();
while(iter.hasNext()){
Map.Entry<String, Object> subcond = iter.next();
if(subcond.getKey().equals("OR")){
//isValid = isValid || test((Set<Map.Entry<String, Object>>) subcond.getValue(), value);
} else if(subcond.getKey().equals("AND")){
//isValid = isValid && test((Set<Map.Entry<String, Object>>) subcond.getValue(), value);
} else if(subcond.getKey().equals("NOT")){

} else {

}
}
return isValid;
}
@Override
public JSONObject query(JSONObject query) {
// the set containing the conditions
Set<Map.Entry<String, Object>> entries = query.toMap().entrySet();
// the JSONArray with containing the records that match the condition
JSONArray array = new JSONArray();
// for each JSONObject inside this structure
this.forEach(new BiConsumer<K,JSONObject>(){
@Override
public void accept(K key, JSONObject value) {
// testing if the current record matches the condition
if(test(entries, value)) array.put(value);
}

});
// returns a JSONObject containing a JSONArray that contains the records that match the condition
return new JSONObject(array);
}
}

我目前停留在测试方法中,该方法实际上应该测试给定的对象是否与给定条件匹配。

我不介意更改 JSON 条件的格式,只要它是JSONObject.

目前,我已经提出了一个部分解决方案,该解决方案构建了一个名为Condition的对象,该对象表示JSONObject中的布尔表达式(不是很有效,但仍然是一个可能的解决方案),这显然目前不起作用,我需要帮助我现在应该做什么

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Condition {
private Condition left, right;
private String boolExpr, key, value;
private boolean not;
private int operationType; // greater then, less then, equal to, greater or equal of, less or equal of
public Condition(Map<String, Object> map) {
Set<Map.Entry<String, Object>> set = map.entrySet();
Iterator<Map.Entry<String, Object>> iterator = set.iterator();
while(iterator.hasNext()){
Object entry = iterator.next();
System.out.println(entry);
System.out.println(entry.getClass());
if(entry instanceof Map.Entry) {
String key = (String) ((Map.Entry) entry).getKey();
switch(key){
case "AND":
case "OR":
this.boolExpr = key;
break;
case "eq":
case "gt":
case "lt":
case "gte":
case "lte":
this.operationType = getOperationTypeFromString(key);
break;
case "NOT":
this.not = true;
break;
default:
this.key = key;
break;
}
}
}
}
public int getOperationTypeFromString(String operation) {
switch(operation){
case "eq":
return 0;
case "gt":
return 1;
case "lt":
return 2;
case "gte":
return 3;
case "lte":
return 4;
default:
return 0;
}
}
}

我宁愿不使用 Condition 类,而只使用 JSONObject。 我正在使用org.json JSON-Java解析器。

编辑:代码更新为使用 org.json。

下面是处理您的示例的工作实现。

实际执行工作的函数是match,它递归遍历过滤器并将每个节点应用于提供的对象。如果给定对象满足给定的筛选器,则该函数返回 true。

从概念上讲,match函数是将过滤语言中的每个构造(ANDOREQLT等)映射到它的Java等价物。 例如AND映射到Stream.allMatchNOT映射到Java!运算符,EQ映射到Object.equals等。J.F.match定义过滤器语言的语义。

我希望代码是不言自明的 - 如果有任何不清楚的地方,请告诉我。

import org.json.*;
import java.io.*;
import java.nio.file.*;
import java.util.List;
import java.util.stream.*;
import static java.util.stream.Collectors.toList;
public class Test {
public static void main(String[] args) throws IOException {
final List<JSONObject> jsObjs =
stream(readJsonArray("users.json"))
.map(JSONObject.class::cast)
.collect(toList());
final JSONObject jsFilter = readJsonObject("filter.json");
final List<JSONObject> matches = applyFilter(jsObjs, jsFilter);
System.out.println(matches);
}
private static List<JSONObject> applyFilter(List<JSONObject> jsObjs, JSONObject jsFilter) {
return jsObjs.stream()
.filter(jsObj -> match(jsObj, jsFilter))
.collect(toList());
}
private static boolean match(JSONObject jsObj, JSONObject jsFilter) {
final String name = getSingleKey(jsFilter);
final Object value = jsFilter.get(name);
switch (name) {
case "AND":
return stream((JSONArray)value)
.map(JSONObject.class::cast)
.allMatch(jse -> match(jsObj, jse));
case "OR":
return stream((JSONArray)value)
.map(JSONObject.class::cast)
.anyMatch(jse -> match(jsObj, jse));
case "NOT":
return !match(jsObj, (JSONObject)((JSONArray)value).get(0));
default:
final JSONObject jsOp = (JSONObject)value;
final String operator = getSingleKey(jsOp);
final Object operand = jsOp.get(operator);
switch (operator) {
case "eq": return jsObj.get(name).equals(operand);
case "lt": return (Integer)jsObj.get(name) < (Integer)operand;
case "gt": return (Integer)jsObj.get(name) > (Integer)operand;
default: throw new IllegalArgumentException("Unexpected operator: " + operator);
}
}
}
private static JSONObject readJsonObject(String fileName) throws IOException {
try (Reader reader = Files.newBufferedReader(Paths.get(fileName))) {
return new JSONObject(new JSONTokener(reader));
}
}
private static JSONArray readJsonArray(String fileName) throws IOException {
try (Reader reader = Files.newBufferedReader(Paths.get(fileName))) {
return new JSONArray(new JSONTokener(reader));
}
}
private static Stream<Object> stream(JSONArray jsa) {
return StreamSupport.stream(jsa.spliterator(), false);
}
private static String getSingleKey(JSONObject jso) {
if (jso.length() != 1) {
throw new IllegalArgumentException("Expected single entry");
} else {
return jso.keySet().iterator().next();
}
}
}

相关内容

  • 没有找到相关文章

最新更新