Home > Software engineering >  Converting Complex Tree Structure to JSON Python
Converting Complex Tree Structure to JSON Python

Time:04-05

I need to convert a Tree with the following class structure:

Class Tree:     
    def __init__(self, data):         
        self.data = data         
        self.and_objects = []         
        self.or_objects = []

Where the data is:

Class Data:     
    def __init__(self, var, operator, value):
        self.var = var
        self.operator = operator
        self.value = value
    def to_json(self):
        return {"var": self.var, "operator": self.operator, "value": self.value}

A simplified example of the data structure:

Root
  andChildren
    x = 0
      andChildren
         a = 1
         b = 2 
    y = 10
      andChildren
         a = 3   
      orChildren
         y = 3
            andChildren
               a = 2
         
  orChildren
    Empty

evaluates to:

((x == 0 and (a == 1 and b == 2)) and ((y == 10 and (a == 3)) or (y == 3 and a == 2))

I need to convert the tree data structure to:

{
   "Search":{
      "Root":{
         "compare_operator":"and",
         "values":[
            {
               "compare_operator":"and",
               "values":[
                  {
                     "var":"x",
                     "operator":"=",
                     "value":"0"
                  },
                  {
                     "compare_operator":"and",
                     "values":[
                        {
                           "var":"a",
                           "operator":"=",
                           "value":"1"
                        },
                        {
                           "var":"b",
                           "operator":"=",
                           "value":"2"
                        }
                     ]
                  }
               ]
            },
            {
               "compare_operator":"or",
               "values":[
                  {
                     "compare_operator":"and",
                     "values":[
                        {
                           "var":"y",
                           "operator":"=",
                           "value":"10"
                        },
                        {
                           "var":"a",
                           "operator":"=",
                           "value":"3"
                        }
                     ]
                  },
                  {
                     "compare_operator":"and",
                     "values":[
                        {
                           "var":"y",
                           "operator":"=",
                           "value":"3"
                        },
                        {
                           "var":"a",
                           "operator":"=",
                           "value":"2"
                        }
                     ]
                  }
               ]
            }
         ]
      }
   }
}

Does anyone have any tips/methods on how to transform this tree data structure to this json structure?

I've tried a couple recursive algorithms, but I can not get them to yield the JSON output needed.

The script that recreates this structure:


Class Tree:     
    def __init__(self, data="root"):         
        self.data = data         
        self.and_objects = []         
        self.or_objects = []
        
Class Data:     
    def __init__(self, var, operator, value):
        self.var = var
        self.operator = operator
        self.value = value
    def to_json(self):
        return {"var": self.var, "operator": self.operator, "value": self.value}
        
def create_search(var, operator, value, parent, comparision="and")
    data = Data(var, operator, value)
    child = Tree(data)
    if comparision == "and":
        parent.and_objects.append(child)
    else:
        parent.or_objects.append(child)
    return child
    
if __name__ == "__main__":
    root_tree = Tree()
    x_temp = create_search("x", "=", "0", root_tree)
    create_search("a", "=", "1", x_temp)
    create_search("b", "=", "2", x_temp)
    
    y_temp = create_search("y", "=", "10", root_tree)
    create_search("a", "=", "3", root_tree, y_temp)
    nested_y_temp = create_search("y", "=", "3", root_tree, y_temp, "or")
    create_search("a", "=", "2", root_tree, nested_y_temp)
    
    # tree data is on root_tree

CodePudding user response:

I would go for a different initial structure. In your structure an AND or OR operator needs to have a Data instance as parent. And a Data instance is combined with both and AND and OR list that depends on it.

I would suggest to allow for a top-level AND or OR operator that has all its operands as children. You could also create separate classes for AND and OR operators, and for EQUALITY operator as well.

Here is how that would look:

class Logical():
    def __init__(self, operator, operands):
        self.operands = operands
        self.operator = operator

    def __str__(self):
        return f" {self.operator} ".join(map(str, self))

    def asdict(self):
        return { 
            "compare_operator": self.operator, 
            "values": [operand.asdict() for operand in self.operands]
        }

class And(Logical):
    def __init__(self, *operands):
        super().__init__("and", operands)

class Or(Logical):
    def __init__(self, *operands):
        super().__init__("or", operands)


class Condition:
    def __init__(self, var, operator, value):
        self.var = var
        self.operator = operator
        self.value = value
        
    def asdict(self):
        return {
            "var": self.var, 
            "operator": self.operator, 
            "value": self.value
        }

class Equal(Condition):
    def __init__(self, var, value):
        super().__init__(var, "=", value)

Example creation of a structure:

expression = And(
    And(
        Equal("x", 0), 
        And(
            Equal("a", 1), 
            Equal("b", 2), 
        ),
    ),
    Or(
        And(
            Equal("y", 10), 
            Equal("a", 3)
        ),
        And(
            Equal("y", 3),
            Equal("a", 2)
        )
    )
)

Turning it to JSON:

import json

result = {
    "Search": {
        "Root": expression.asdict()
    }
}

print(json.dumps(result, indent=4))

This prints:

{
    "Search": {
        "Root": {
            "compare_operator": "and",
            "values": [
                {
                    "compare_operator": "and",
                    "values": [
                        {
                            "var": "x",
                            "operator": "=",
                            "value": 0
                        },
                        {
                            "compare_operator": "and",
                            "values": [
                                {
                                    "var": "a",
                                    "operator": "=",
                                    "value": 1
                                },
                                {
                                    "var": "b",
                                    "operator": "=",
                                    "value": 2
                                }
                            ]
                        }
                    ]
                },
                {
                    "compare_operator": "or",
                    "values": [
                        {
                            "compare_operator": "and",
                            "values": [
                                {
                                    "var": "y",
                                    "operator": "=",
                                    "value": 10
                                },
                                {
                                    "var": "a",
                                    "operator": "=",
                                    "value": 3
                                }
                            ]
                        },
                        {
                            "compare_operator": "and",
                            "values": [
                                {
                                    "var": "y",
                                    "operator": "=",
                                    "value": 3
                                },
                                {
                                    "var": "a",
                                    "operator": "=",
                                    "value": 2
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    }
}
  • Related