Representing logic as data in JSON

前端 未结 12 1465
眼角桃花
眼角桃花 2021-01-29 21:37

For business reasons we need to externalize some conditional logic into external files: preferably JSON.

A simple filter-by scenario could be handled by adding a node a

相关标签:
12条回答
  • 2021-01-29 22:07

    The first came to mind would be the recurisve

    dict1={'$lte':'<','$nin':'not in '}
    
    def updateOp(subdictItem):
    
        for ites in subdictItem:
            ops = ites
            print dict1.get(ops), subdictItem.get(ops), type(subdictItem.get(ops))
            if type(subdictItem.get(ops)) is list:
                valuelist=subdictItem.get(ops)
                strlist=' ,'.join([str(x) for x in valuelist])
                sub = dict1.get(ops) + "(" +strlist +")"
            else:
                sub = dict1.get(ops) +' ' + str(subdictItem.get(ops))
        return sub
    
    def jsonString(input_dict):
        items=''
        itemslist=[]
        list = []
        for item in input_dict:
            op=item
            itemssublist=[]
    
            # print "item",op
            for subitem in input_dict.get(op):
                # print("subitem",subitem)
                for ite in subitem:
                    if ite not in ('and','or'):
                        # print('ite_raw',ite,subitem.get(ite))
                        sub=''
                        if type(subitem.get(ite)) is dict:
                            sub=updateOp(subitem.get(ite))
                        else:
                            sub='=' + str(subitem.get(ite))
                        itemssublist.append(ite+sub)
                    else:
                        item1=jsonString(subitem)
                        itemssublist.append(item1)
    
            delimiter=" "+op+ " "
            items= "("+delimiter.join(itemssublist)+")"
        return items 
    
    
    
    
    
    if __name__ == "__main__":
    
        input_dict={}
        with open('ops.json','r') as f:
            input_dict=json.load(f)
    
        print input_dict
    
        test= jsonString(input_dict)
    
    #result : (age< 3 or name=Joe or (age=5 and age not in (1 ,2 ,3)))
    ops.json file:
    {
       "or":[
          {
             "age":{
                "$lte":3
             }
          },
          {
             "name":"Joe"
          },
          {
             "and":[
                {
                   "age":5
                },
                {
                   "age ":{
                      "$nin":[
                         1,
                         2,
                         3
                      ]
                   }
                }
             ]
          }
       ]
    }
    
    0 讨论(0)
  • 2021-01-29 22:13

    If you must implement 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.

    For example:

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

    would represent 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.

    0 讨论(0)
  • 2021-01-29 22:15

    Following Jeremy Wadhams comment, I implemented a parser I hope it can help you:

    https://play.golang.org/p/QV0FQLrTlyo

    The idea is to set all logic operators in special keys with $ character like $and or $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) )  )  
    
    0 讨论(0)
  • 2021-01-29 22:15

    Formula parser + a bit of JS codes to put data into formulas, is another solution described with example in this answer.

    0 讨论(0)
  • 2021-01-29 22:17

    I had a similar need (to build up a sql where clause in javascript). I create dthe following javascript function:

      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:

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

    I need to add some type conversions and other operators, but the basic structure works.

    0 讨论(0)
  • 2021-01-29 22:19

    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

    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.

    0 讨论(0)
提交回复
热议问题