在JSON中将逻辑表示为数据

出于商业原因,我们需要将一些条件逻辑外部化为外部文件:最好是JSON。

一个简单的过滤scheme可以通过添加一个节点来处理,如下所示:

"filter": [ { "criteria": "status", "value": "open", "condition": "==" } ] 

数组中的其他值可以处理多个条件。

 "filter": [ { "criteria": "status", "value": "open", "condition": "==" }, { "criteria": "condition2", "value": "value2", "condition": "==" } ] 

然而,当我们处理涉及AND或OR的复杂条件时,会有点混淆。

问题:在JSON中表示这种逻辑是否有一种标准化(甚至被广泛接受)的格式? 如果这取决于你,你会怎么做?

注:第一个答案已经成为一个可编辑的维基,所以任何人都可以改善它。

如果你必须使用标准的JSON实现这个,我会推荐类似于Lisp的“Sexpression式”。 条件可以是普通对象,也可以是第一个条目是join它们的逻辑操作的数组。

例如:

 ["AND", {"var1" : "value1"}, ["OR", { "var2" : "value2" }, { "var3" : "value3" } ] ] 

将代表var1 == value1 AND (var2 == value2 OR var3 == value3)

如果你喜欢简洁而不是一致性,你也可以允许一个对象具有多个属性,这些属性将隐含地被AND连接。 例如, { "a": "b", "c": "d" }等效于["AND", { "a": "b" }, { "c": "d" }] 。 但是有些情况下(比如这个例子),前面的语法不能忠实地表示书写的状态; 你需要额外的技巧来翻译条件或使用虚拟属性名称。 后者的语法应该始终工作。

我需要一个格式,将:

  1. 支持比较平等以外的比较。
  2. 让variables出现在任何位置,而不仅仅是比较文字。
  3. 一致,简洁,安全和可扩展。

所以我build立了一个叫做JsonLogic的格式。 规则是JSON对象,操作符位于键位置,值位置中有一个或一个参数数组。 (受Amazon CloudFormationfunction的启发)任何参数都可以是另一个规则,因此您可以构build任意深度的逻辑。

我还为它编写了两个parsing器: JsonLogic for JavaScript和JsonLogic for PHP 。

cHao的例子会写成

 { "and", [ {"==", [ {"var" : "var1"}, "value1" ]}, { "or", [ {"==", [ {"var" : "var2"}, "value2" ]}, {"==", [ {"var" : "var3"}, "value3" ]} ]} ]} 

var这里是运算符获得“数据”对象的属性,与“规则”对象一起传递给parsing器,例如:

 jsonLogic( {"==", [{"var":"filling"}, "apple"]} // rule, is this pie apple? {"filling":"apple", "temperature":100} // data, a pie I'm inspecting ); // true 

有更多的可能的运算符(大于,不等于,数组,三元等),这两个parsing器都可以在GitHub上(unit testing和文档)。

我有一个类似的需求(在JavaScript中build立一个SQL where子句)。 我创build了以下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; } 

我创build我的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 } } }; 

当我通过我的queryOperation ParseQuery它返回((tradedate = Thu Jul 24 17:30:37 EDT 2014))AND(((systemid = 9))OR((systemid = 10)))

我需要添加一些types转换和其他操作符,但基本结构起作用。

顺便提一下, IBM DB2支持以JSON编码的逻辑语句 。

布尔操作看起来像cHao的解决scheme和Amazon CloudFormation之间的交叉:

 {"$and":[{"age":5},{"name":"Joe"}]} 

比较操作对于我来说就像音译SQL一样。 (而不是Amazon或Russellg或cHao的抽象语法树)。

 {"age":{"$lt":3}} 

请检查(JSL)[ https://www.npmjs.com/package/lib-jsl ]。 它似乎符合给出的描述。

这是一个示例:

 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)); 

答复是:

 [ { "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" } ] 

主要工作由规则workInProgress中定义的查询完成:

 [ { workInProgress : '$bug'}, { bug : '$bug'}, { $or : [ { $bind : [ '$bug', { status : 'open'} ] }, { $bind : [ '$bug', { status : 'resolved'} ] } ] } ] 

这条规则可以被理解为:

为了满足workInProgress的查询,我们定义一个variables{workInProgress : '$bug'} ,然后我们使用规则的下一部分{bug : '$bug'}来匹配数据库中的所有错误。 这部分匹配所有的错误,因为对象的形状(它是键:'错误')匹配数据库中的错误logging。 该规则进一步要求$ bugvariables在包含相关状态值(打开和closures)的模式下绑定(编辑)。 只有那些在$ bug中的状态值满足规则主体的所有部分的buglogging才有资格获得结果。

最终使用变换规范transform : '$wip'结果: transform : '$wip' ,它实际上要求查询的$ wipvariables中返回的所有值的数组。

我的同事提出了这个可能的解决办法

“所有OR条件将是一个数组而AND条件将是对象,

例如,OR可以匹配数组中的任何对象:

 [ { "var1":"value1" }, { "var2":"value2" }, { "var3":"value3" } ] 

将是

 { "var1":"val1", "var2":"val2", "var3":"val3" }