将逻辑表示为JSON中的数据

Viv*_*ira 52 algorithm json

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

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

"filter": [
  {
    "criteria": "status",
    "value": "open",
    "condition": "=="
  }
]
Run Code Online (Sandbox Code Playgroud)

多个条件可以通过数组中的其他值来处理.

"filter": [
  {
    "criteria": "status",
    "value": "open",
    "condition": "=="
  },
  {
    "criteria": "condition2",
    "value": "value2",
    "condition": "=="
  }
]
Run Code Online (Sandbox Code Playgroud)

但是,当我们处理涉及AND或OR的复杂条件时,它会有点混乱.

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

注意:第一个答案是一个可编辑的维基,所以任何人都可以改进它.

cHa*_*Hao 55

如果你必须使用标准JSON实现它,我建议类似于Lisp的"S表达式".条件可以是普通对象,也可以是第一个条目是连接它们的逻辑操作的数组.

例如:

["AND",
    {"var1" : "value1"},
    ["OR",
        { "var2" : "value2" },
        { "var3" : "value3" }
    ]
]
Run Code Online (Sandbox Code Playgroud)

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

如果您更喜欢简洁而不是一致性,那么您还可以允许对象具有多个属性,这些属性将隐式地由AND连接.例如,{ "a": "b", "c": "d" }相当于["AND", { "a": "b" }, { "c": "d" }].但是有些情况(比如示例),前一种语法不能忠实地表示写入的条件; 你需要额外的技巧,比如翻译条件或使用虚拟属性名称.后一种语法应始终有效.

  • "任何足够复杂的C或Fortran程序都包含一个临时的,非正式指定的,错误缠身的,一半Common Lisp的缓慢实现." - 格林斯普的第十个编程规则 (6认同)

Jer*_*ams 33

我需要一种格式:

  1. 支持除相等之外的比较.
  2. 让变量出现在任何位置,而不仅仅是与文字进行比较.
  3. 保持一致,简洁,安全和可扩展.

所以我构建了一个我称之为JsonLogic的格式.规则是JSON对象,操作符位于键位置,值位置中有一个或一组参数.(受Amazon CloudFormation函数的启发.)任何参数都可以是另一个规则,因此您可以构建任意深度的逻辑.

我还为它编写了两个解析器:JsonLogic for JavaScriptJsonLogic for PHP.

cHao的例子将写成

{ "and", [
    {"==", [ {"var" : "var1"}, "value1" ]},
    { "or", [
        {"==", [ {"var" : "var2"}, "value2" ]},
        {"==", [ {"var" : "var3"}, "value3" ]}
    ]}
]}
Run Code Online (Sandbox Code Playgroud)

var 这里是获取"data"对象的属性的运算符,与"rule"对象一起传递给解析器,例如:

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

有更多可能的运算符(大于,非等于,数组内,三元等),并且两个解析器都可以在GitHub上使用(带有单元测试和文档).


Rus*_*llg 6

我有类似的需求(在 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;
    }
Run Code Online (Sandbox Code Playgroud)

我创建我的 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
                }
            }
        };
Run Code Online (Sandbox Code Playgroud)

当我将 queryOperation 传递给 ParseQuery 时,它返回 ((tradedate= Thu Jul 24 17:30:37 EDT 2014)) AND (((systemid= 9)) OR ((systemid= 10)))

我需要添加一些类型转换和其他运算符,但基本结构有效。


NSj*_*nas 6

我提出这种格式的主要目标是尽可能接近实际的 SQL。

这是打字稿中的类型定义:

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> { }
Run Code Online (Sandbox Code Playgroud)

或者 BNF(是吗?我的计算机老师不会感到自豪)

WHEREGROUP: = [ CONDITION | ('AND'|'OR') | WHEREGROUP ]
CONDITION: = {field, opp, val}
Run Code Online (Sandbox Code Playgroud)

具有以下解析规则:

  1. AND是可选的(我通常添加它是为了便于阅读)。如果LogicalOperator条件之间省略了逻辑,它会自动将它们连接起来AND
  2. 内部数组被解析为嵌套组(EG 被包裹在()
  3. 这种类型不限制连续的多个逻辑运算符(不幸的是)。我只使用最后一个来处理这个问题,尽管我可能会抛出一个运行时错误。

以下是一些示例(打字稿游乐场链接):

1 和 2(并推断)

[
    { field: 'name', opp: '=', val: '123' },
    { field: 'otherfield', opp: '>=', val: 123 }
]
Run Code Online (Sandbox Code Playgroud)

1 或 2

[
    { field: 'name', opp: '=', val: '123' },
    'OR',
    { field: 'annualRevenue', opp: '>=', val: 123 }
]
Run Code Online (Sandbox Code Playgroud)

(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 }
    ]
]
Run Code Online (Sandbox Code Playgroud)

1 和(2 或 3)

[
    { field: 'name', opp: '=', val: '123' },
    'AND',
    [
        { field: 'annualRevenue', opp: '>=', val: 123 },
        'OR',
        { field: 'active', opp: '=', val: true }
    ]
]
Run Code Online (Sandbox Code Playgroud)

1 和 2 或 3

[
    { field: 'name', opp: '=', val: '123' },
    'AND',
    { field: 'annualRevenue', opp: '>=', val: 123 },
    'OR',
    { field: 'active', opp: '=', val: true }
]
Run Code Online (Sandbox Code Playgroud)

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' }
        ]
    ]
]
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,如果你要删除,和 属性名称,然后只需将 替换为[]()你基本上就会得到 SQL 格式的条件

  • 您可能对 http://jsonlogic.com/ 感兴趣,它似乎采用了非常相似的方法。 (2认同)

Jer*_*ams 5

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

布尔运算看起来像cHao的解决方案与Amazon CloudFormation之间的交叉:

{"$and":[{"age":5},{"name":"Joe"}]}
Run Code Online (Sandbox Code Playgroud)

在我看来,比较操作就像音译SQL一样。(而不是Amazon或Russellg或cHao向抽象语法树的迁移。)

{"age":{"$lt":3}}
Run Code Online (Sandbox Code Playgroud)