将逻辑表示为 JSON 中的数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20737045/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Representing logic as data in JSON
提问by Vivek Kodira
For business reasons we need to externalize some conditional logic into external files: preferably JSON.
出于业务原因,我们需要将一些条件逻辑外部化到外部文件中:最好是 JSON。
A simple filter-by scenario could be handled by adding a node as follows:
一个简单的过滤场景可以通过添加一个节点来处理,如下所示:
"filter": [
{
"criteria": "status",
"value": "open",
"condition": "=="
}
]
Multiple conditions could be handled by additional values in the array.
数组中的附加值可以处理多个条件。
"filter": [
{
"criteria": "status",
"value": "open",
"condition": "=="
},
{
"criteria": "condition2",
"value": "value2",
"condition": "=="
}
]
However, it gets a little confusing when we have handle complex conditions involving ANDs or ORs.
然而,当我们处理涉及 AND 或 OR 的复杂条件时,它会变得有点混乱。
Question: is there a standardized (or even widely accepted) format for representing such logic within JSONs? How would you do it if it were up to you?
问题:是否有标准化(甚至被广泛接受)的格式来表示 JSON 中的此类逻辑?如果由你决定,你会怎么做?
NOTE: The first answer has been made an editable wiki so it can be improved by anyone who feels it can be.
注意:第一个答案已成为可编辑的 wiki,因此任何认为可以改进的人都可以对其进行改进。
采纳答案by cHao
If you mustimplement this using standard JSON, i'd recommend something akin to Lisp's "S-expressions". A condition could be either a plain object, or an array whose first entry is the logical operation that joins them.
如果您必须使用标准 JSON来实现它,我会推荐类似于 Lisp 的“S-表达式”的东西。条件可以是一个普通对象,也可以是一个数组,其第一个条目是连接它们的逻辑操作。
For example:
例如:
["AND",
{"var1" : "value1"},
["OR",
{ "var2" : "value2" },
{ "var3" : "value3" }
]
]
would represent var1 == value1 AND (var2 == value2 OR var3 == value3).
将代表var1 == value1 AND (var2 == value2 OR var3 == value3).
If you prefer brevity over consistency, you could also allow an object to have multiple properties, which would implicitly be joined by an AND. For example, { "a": "b", "c": "d" }would be equivalent to ["AND", { "a": "b" }, { "c": "d" }]. But there are cases (like the example) where the former syntax can not faithfully represent the condition as written; you'd need additional trickery like translating the condition or using dummy property names. The latter syntax should always work.
如果您更喜欢简洁而不是一致性,您还可以允许一个对象具有多个属性,这些属性将通过 AND 隐式连接。例如,{ "a": "b", "c": "d" }将等效于["AND", { "a": "b" }, { "c": "d" }]. 但在某些情况下(如示例),前一种语法不能如实表示所写的条件;您需要额外的技巧,例如翻译条件或使用虚拟属性名称。后一种语法应该始终有效。
回答by Jeremy Wadhams
I needed a format that would:
我需要一种格式:
- Support comparisons other than equality.
- Let variables appear in any position, not just be compared to literals.
- Be consistent, terse, secure, and extensible.
- 支持除相等以外的比较。
- 让变量出现在任何位置,而不仅仅是与文字进行比较。
- 保持一致、简洁、安全和可扩展。
So I built up a format I'm calling JsonLogic. A rule is a JSON object, with the operator in the key position, and one or an array of arguments in the value position. (Inspired by Amazon CloudFormation functions.) Any argument can be another rule, so you can build arbitrarily deep logic.
所以我建立了一个我称之为JsonLogic的格式。规则是一个 JSON 对象,操作符位于键位置,一个或一组参数位于值位置。(受Amazon CloudFormation 函数的启发。)任何参数都可以是另一条规则,因此您可以构建任意深度的逻辑。
I've also written two parsers for it: JsonLogic for JavaScriptand JsonLogic for PHP.
我还为它编写了两个解析器:用于 JavaScript 的JsonLogic和用于 PHP 的 JsonLogic。
cHao's example would be written as
cHao 的例子可以写成
{ "and", [
{"==", [ {"var" : "var1"}, "value1" ]},
{ "or", [
{"==", [ {"var" : "var2"}, "value2" ]},
{"==", [ {"var" : "var3"}, "value3" ]}
]}
]}
varhere is the operator to get a property of the "data" object, passed along with the "rule" object to the parser, e.g.:
var这是获取“数据”对象属性的运算符,与“规则”对象一起传递给解析器,例如:
jsonLogic(
{"==", [{"var":"filling"}, "apple"]} // rule, is this pie apple?
{"filling":"apple", "temperature":100} // data, a pie I'm inspecting
);
// true
There are lots more possible operators (greater than, not-equals, in-array, ternary, etc) and both parsers are available on GitHub (with unit tests and documentation).
有更多可能的运算符(大于、不等于、数组中、三元等)并且两个解析器都可以在 GitHub 上找到(带有单元测试和文档)。
回答by Jeremy Wadhams
By the way, IBM DB2 supports logic statements encoded in JSON.
顺便说一下,IBM DB2 支持以 JSON 编码的逻辑语句。
Boolean operations look like a cross between cHao's solution and Amazon CloudFormation:
布尔运算看起来像是 cHao 的解决方案和 Amazon CloudFormation 的结合:
{"$and":[{"age":5},{"name":"Joe"}]}
Comparison operations look, to me, like transliterated SQL. (Instead of Amazon or Russellg or cHao's movement toward an abstract syntax tree.)
在我看来,比较操作就像音译 SQL。(而不是 Amazon 或 Russellg 或 cHao 的抽象语法树运动。)
{"age":{"$lt":3}}
回答by Russellg
I had a similar need (to build up a sql where clause in javascript). I create dthe following javascript function:
我有类似的需求(在 javascript 中建立一个 sql where 子句)。我创建了以下 javascript 函数:
function parseQuery(queryOperation){
var query="";
if (queryOperation.operator == 'and')
query = "(" + parseQuery(queryOperation.leftOp) + ") AND (" + parseQuery(queryOperation.rightOp) + ")";
if (queryOperation.operator == 'or')
query = "(" + parseQuery(queryOperation.leftOp) + ") OR (" + parseQuery(queryOperation.rightOp) + ")";
if (queryOperation.operator == '=')
query = "(" + queryOperation.leftOp +" = "+ queryOperation.rightOp + ")";
return query;
}
I create my queryOperation Like this:
我创建我的 queryOperation 像这样:
var queryObject = {
operator: 'and',
leftOp: {
leftOp: 'tradedate',
operator: '=',
rightOp: new Date()
},
rightOp: {
operator: 'or',
leftOp: {
leftOp: 'systemid',
operator: '=',
rightOp: 9
},
rightOp: {
leftOp: 'systemid',
operator: '=',
rightOp:10
}
}
};
When I pass my queryOperation to ParseQuery it returns ((tradedate= Thu Jul 24 17:30:37 EDT 2014)) AND (((systemid= 9)) OR ((systemid= 10)))
当我将 queryOperation 传递给 ParseQuery 时,它返回 ((tradedate= Thu Jul 24 17:30:37 EDT 2014)) AND (((systemid= 9)) OR ((systemid= 10)))
I need to add some type conversions and other operators, but the basic structure works.
我需要添加一些类型转换和其他运算符,但基本结构有效。
回答by NSjonas
I came up with this format with the primary goal of reading as close as possible to actually SQL.
我提出这种格式的主要目标是尽可能接近实际的 SQL。
Here's the Type def in typescript:
这是打字稿中的 Type def:
type LogicalOperator = 'AND' | 'OR';
type Operator = '=' | '<=' | '>=' | '>' | '<' | 'LIKE' | 'IN' | 'NOT IN';
type ConditionParams = {field: string, opp: Operator, val: string | number | boolean};
type Conditions = ConditionParams | LogicalOperator | ConditionsList;
interface ConditionsList extends Array<Conditions> { }
Or BNF (ish? my cs teachers wouldn't be proud)
或 BNF(是吗?我的 cs 老师不会感到自豪)
WHEREGROUP: = [ CONDITION | ('AND'|'OR') | WHEREGROUP ]
CONDITION: = {field, opp, val}
With the following Parsing Rules:
使用以下解析规则:
ANDis optional (I typically add it for readability). If logicalLogicalOperatoris left out between conditions, it will automatically joins them withAND- Inner arrays are parsed as nested groups (EG get wrapped in
()) - this type does not restrict multiple logical operators consecutively (unfortunately). I handled this by just using the last one, although I could have thrown a runtime error instead.
AND是可选的(我通常添加它以提高可读性)。如果逻辑LogicalOperator在条件之间被遗漏,它会自动将它们与AND- 内部数组被解析为嵌套组(EG 被包裹在 中
()) - 这种类型不会连续限制多个逻辑运算符(不幸的是)。我只使用最后一个来处理这个问题,尽管我可能会抛出一个运行时错误。
Here are some examples (typescript playground link):
以下是一些示例(打字稿游乐场链接):
1 AND 2(AND inferred)
1 AND 2(AND 推断)
[
{ field: 'name', opp: '=', val: '123' },
{ field: 'otherfield', opp: '>=', val: 123 }
]
1 OR 2
1 或 2
[
{ field: 'name', opp: '=', val: '123' },
'OR',
{ field: 'annualRevenue', opp: '>=', val: 123 }
]
(1 OR 2) AND (3 OR 4)
(1 或 2) 和 (3 或 4)
[
[
{ field: 'name', opp: '=', val: '123' },
'OR',
{ field: 'name', opp: '=', val: '456' }
],
'AND',
[
{ field: 'annualRevenue', opp: '>=', val: 123 },
'OR',
{ field: 'active', opp: '=', val: true }
]
]
1 AND (2 OR 3)
1 与(2 或 3)
[
{ field: 'name', opp: '=', val: '123' },
'AND',
[
{ field: 'annualRevenue', opp: '>=', val: 123 },
'OR',
{ field: 'active', opp: '=', val: true }
]
]
1 AND 2 OR 3
1 和 2 或 3
[
{ field: 'name', opp: '=', val: '123' },
'AND',
{ field: 'annualRevenue', opp: '>=', val: 123 },
'OR',
{ field: 'active', opp: '=', val: true }
]
1 OR (2 AND (3 OR 4))
1 或(2 与(3 或 4))
[
{ field: 'name', opp: '=', val: '123' },
'OR',
[
{ field: 'annualRevenue', opp: '>=', val: 123 },
'AND',
[
{ field: 'active', opp: '=', val: true },
'OR',
{ field: 'accountSource', opp: '=', val: 'web' }
]
]
]
As you can see, if you were to remove ,and property names, then just replace the []with (), you'd basically have the condition in SQL format
如您所见,如果您要删除,和属性名称,那么只需替换[]with (),您基本上就拥有 SQL 格式的条件
回答by omotto
Following Jeremy Wadhams comment, I implemented a parser I hope it can help you:
根据 Jeremy Wadhams 的评论,我实现了一个解析器,希望它可以帮助您:
https://play.golang.org/p/QV0FQLrTlyo
https://play.golang.org/p/QV0FQLrTlyo
The idea is to set all logic operators in special keys with $character like $andor $lte.
这个想法是将所有逻辑运算符设置在特殊键中,$字符为$andor $lte。
As an example:
举个例子:
{
"$or":[
{
"age":{
"$lte":3
}
},
{
"name":"Joe"
},
{
"$and":[
{
"age":5
},
{
"age ":{
" $nin ":[
1,
2,
3
]
}
}
]
}
]
}
Regards.
问候。
Is translated as:
译为:
( age <= 3 OR name = Joe OR ( age = 5 AND age NOT IN (1,2,3) ) )
回答by Vivek Kodira
My colleague suggested this possible solution:
我的同事提出了这个可能的解决方案:
"all OR conditions would be an array while AND conditions would be objects,
“所有 OR 条件将是一个数组,而 AND 条件将是对象,
For example,OR can match any of the objects in the array:
例如,OR 可以匹配数组中的任何对象:
[
{
"var1":"value1"
},
{
"var2":"value2"
},
{
"var3":"value3"
}
]
AND would be
并且会
{
"var1":"val1",
"var2":"val2",
"var3":"val3"
}
回答by Ruchir Walia
Please check out (JSL)[https://www.npmjs.com/package/lib-jsl]. It seems to fit the description given.
请查看(JSL)[ https://www.npmjs.com/package/lib-jsl]。它似乎符合给出的描述。
Here is a sample :
这是一个示例:
var JSL = require('lib-jsl');
var bugs = [
[{ bug : { desc: 'this is bug1 open', status : 'open' } }],
[{ bug : { desc: 'this is bug2 resolved', status : 'resolved' } }],
[{ bug : { desc: 'this is bug3 closed' , status : 'closed' } }],
[{ bug : { desc: 'this is bug4 open', status : 'open' } }],
[{ bug : { desc: 'this is bug5 resolved', status : 'resolved' } }],
[{ bug : { desc: 'this is bug6 open', status : 'open' } }],
[ { workInProgress : '$bug'},
{ bug : '$bug'},
{ $or : [
{ $bind : [ '$bug', { status : 'open'} ] },
{ $bind : [ '$bug', { status : 'resolved'} ] }
] }
]
];
var query = [{workInProgress : '$wip'}]
var transform = '$wip'
var jsl = new JSL ({
rules : bugs,
query : query,
transform : transform
});
var retval = jsl.run();
console.log(JSON.stringify(retval, null,2));
The response is :
回应是:
[
{
"desc": "this is bug1 open",
"status": "open"
},
{
"desc": "this is bug2 resolved",
"status": "resolved"
},
{
"desc": "this is bug4 open",
"status": "open"
},
{
"desc": "this is bug5 resolved",
"status": "resolved"
},
{
"desc": "this is bug6 open",
"status": "open"
}
]
The main work is done by the query defined in the rule workInProgress :
主要工作由规则 workInProgress 中定义的查询完成:
[ { workInProgress : '$bug'},
{ bug : '$bug'},
{ $or : [
{ $bind : [ '$bug', { status : 'open'} ] },
{ $bind : [ '$bug', { status : 'resolved'} ] }
] }
]
This rule can be read as :
这条规则可以理解为:
To satisfy the query with workInProgress, we define a variable {workInProgress : '$bug'}, which we then proceed to match against all bugs in the database using the next part of the rule {bug : '$bug'}. This part matches all bugs since the shape of the object (it's keys: 'bug') matches the bug records in the database. The rule further asks the $bug variable to be $bind(ed) against patterns containing relevant status values (open and closed) within a $or. Only those bug records whose status value in $bug satisfies all parts of the rule's body qualify for the result.
为了满足 workInProgress 的查询,我们定义了一个变量{workInProgress : '$bug'},然后我们使用规则的下一部分继续匹配数据库中的所有错误{bug : '$bug'}。这部分匹配所有错误,因为对象的形状(它的键:'bug')与数据库中的错误记录匹配。该规则进一步要求 $bug 变量对包含在 $or 中的相关状态值(打开和关闭)的模式进行 $bind(ed)。只有 $bug 中的状态值满足规则正文所有部分的那些错误记录才有资格获得结果。
The result is finally transformed using the transform specification : transform : '$wip'which literally asks for an array of all values returned in the $wip variable of the query.
结果最终使用转换规范进行转换:transform : '$wip'它实际上要求查询的 $wip 变量中返回的所有值的数组。
回答by edW
Logic can be implemented with "logicOp": "Operator" on a "set": ["a","b" ...] For cHau's example:
逻辑可以用 "logicOp": "Operator" on a "set": ["a","b" ...] 来实现,例如 cHau 的例子:
"var": {
"logicOp": "And",
"set": ["value1",
{
"LogicOp": "Or",
"set": ["value2", "value3"]
}
]
}
There can also be other attributes/operations for the set for example
例如,该集合还可以有其他属性/操作
"val": { "operators": ["min": 0, "max": 2], "set": ["a", "b", "c"] }
For a sunday with two scoops of one or more icecream types, 1 toppings and whipcream
一个星期天,两勺一种或多种冰淇淋,1 种配料和奶油
"sunday": {
"icecream": {
"operators": [ "num": 2,
"multipleOfSingleItem": "true"],
"set": ["chocolate", "strawberry", "vanilla"]
},
"topping": {
"operators": ["num": 1],
"set": ["fudge", "caramel"]
},
"whipcream": "true"
}
回答by Karthik
I just wanted to help by defining a parsing logic in JavaScript for the JSON structure mentioned in the answer: https://stackoverflow.com/a/53215240/6908656
我只是想通过在 JavaScript 中为答案中提到的 JSON 结构定义解析逻辑来提供帮助:https: //stackoverflow.com/a/53215240/6908656
This would be helpful for people having a tough time in writing a parsing logic for this.
这对于在为此编写解析逻辑时遇到困难的人会很有帮助。
evaluateBooleanArray = (arr, evaluated = true) => {
if (arr.length === 0) return evaluated;
else if (typeof arr[0] === "object" && !Array.isArray(arr[0])) {
let newEvaluated = checkForCondition(arr[0]);
return evaluateBooleanArray(arr.splice(1), newEvaluated);
} else if (typeof arr[0] === "string" && arr[0].toLowerCase() === "or") {
return evaluated || evaluateBooleanArray(arr.splice(1), evaluated);
} else if (typeof arr[0] === "string" && arr[0].toLowerCase() === "and") {
return evaluated && evaluateBooleanArray(arr.splice(1), evaluated);
} else if (Array.isArray(arr[0])) {
let arrToValuate = [].concat(arr[0]);
return evaluateBooleanArray(
arr.splice(1),
evaluateBooleanArray(arrToValuate, evaluated)
);
} else {
throw new Error("Invalid Expression in Conditions");
}
};
So the param arr here would be an array of conditions defined in the format as described by the attached link.
因此,这里的参数 arr 将是按附加链接描述的格式定义的条件数组。

