skip to Main Content

I am trying to build a Tree based on data to be found in a dictionary. I know that this could be achieved using recursion, but I am facing troubles solving this problem.
The goal would be to construct a Tree in the form of:

class Tree():
def __init__(self, data) -> None:
    self.data = data
    self.children = []
def addChildren(self, child):
    self.children.append(child)

The following dictionary should be "parsed" and represented by a Tree.

{
   "PaymentCoverageRequestResource":{
      "required":[
         "accountId",
         "paymentCoverageRequestId"
      ],
      "type":"object",
      "properties":{
         "paymentCoverageRequestId":{
            "maxLength":35,
            "type":"string",
            "description":"Identification of the payment Coverage Request"
         },
         "payee":{
            "maxLength":70,
            "type":"string",
            "description":"The merchant where the card is accepted as information to the PSU."
         },
         "instructedAmount":{
            "type":"object",
            "properties":{
               "amount":{
                  "maxLength":70,
                  "type":"string",
                  "description":"The merchant where the card is accepted as information to the PSU."
               },
               "currency":{
                  "maxLength":3,
                  "type":"string",
                  "description":"The merchant where the card is accepted as information to the PSU."
               }
            }
         },
         "accountId":{
            "$ref":"another reference"
         }
      },
      "description":"Payment coverage request structure.nThe request must rely either on a cash account or a payment card.nThe [instructedAmount] property is the payment account on wihich the request is processed. This amount must be positive.nAmounts must always be set as positive values.n",
      "example":"{n  "paymentCoverageRequestId" : "MyCoverage123456",n  "instructedAmount" : {n    "amount" : 12345.0,n    "currency" : "EUR"n  },n  "accountId" : {n    "iban" : "YY13RDHN98392489481620896668799742"n  }n}",
      "x-definition-type":"Resources"
   }
}

A node is considered to be a parent-node, if and only if it contains the key-value pair

"type":"object"

Its children are all the key-value pairs found in "properties".

I tried to solve this problem using the following code, but it am lacking some experience.

def parse_json(requestBody : dict):
    def parse_json_rec(tree : Tree, requestBody : dict):
        #something ?
        if len(requestBody) == 0:
            return tree
        
        (k, v), = requestBody.items()
        requestBody.pop(k)
        print(k)
        
        if v['type'] == 'object': # OR ARRAY
            parent_node = Tree(k)
            print(v)
            return parse_json_rec(tree.addChildren(parse_json_rec(parent_node, v), requestBody))
        else:
            leaf_node = Tree(k)
            tree.addChildren(leaf_node)
            return parse_json_rec(tree, requestBody)
        pass
    root = Tree("root")
    return parse_json_rec(root, requestBody)

The result I would like to achieve is a Tree containing multiple nodes as represented here:

PaymentCoverageRequestResource
     paymentCoverageRequestId
     payee
     instructedAmount
          amount
          currency
     accountId

2

Answers


  1. There are a couple issues I see that might be causing you trouble are:

    1. The weird pattern trying to pop items from the input, and doing recursion on the same-level when there are multiple leaves.
    >>> d = {'a':1, 'b': 2, 'c': 3}
    >>> (k,v), = d.items()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: too many values to unpack (expected 1)
    

    Consider instead, just making a loop over the properties instead of doing recursion on the same level, I think it’d be easier to understand.

    def parse_tree(node):
      for k,v in node.items():
        if is leaf: ...
        if is node: ... tree.addChild(k, parse_tree(v))
    
    1. What does tree.addChildren return, and is that the right thing to pass to parse_json_rec?
    Login or Signup to reply.
  2. I reasonably created a package AbstractTree which can solve this:

    import abstracttree
    from abstracttree import print_tree
    
    
    class Tree(abstracttree.DownTree):
        def __init__(self, name, data):
            self.name = name
            self.data = data
    
        @property
        def children(self):
            if self.data.get("type") == "object":
                return [Tree(k, v) for k, v in self.data["properties"].items()]
            else:
                return ()
    
        def __str__(self):
            return str(self.name)
    
    
    [item] = data.items()
    tree = Tree(*item)
    print_tree(tree)
    

    The output looks like this:

    PaymentCoverageRequestResource
    ├─ paymentCoverageRequestId
    ├─ payee
    ├─ instructedAmount
    │  ├─ amount
    │  └─ currency
    └─ accountId
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search