code: def unflatten(processed, merge_rules):
      
      unflattened = OrderedDict()
  
      for key in processed:
          current_node = unflattened
          for end, part in enumerate(key, 1):
              # If this is a path to an item of an array.
              # See http://standard.open-contracting.org/1.1-dev/en/schema/merging/#identifier-merge
              if isinstance(part, IdValue):
                  # If the `id` of an object in the array matches, change into it.
                  for node in current_node:
                      if isinstance(node, IdDict) and node.identifier == part.identifier:
                          current_node = node
                          break
                  # Otherwise, append a new object, and change into it.
                  else:
                      new_node = IdDict()
                      new_node.identifier = part.identifier
                      # If the original object had an `id` value, set it.
                      if part.original_value is not None:
                          new_node['id'] = part.original_value
                      current_node.append(new_node)
                      current_node = new_node
                  continue
  
              # Otherwise, this is a path to a property of an object.
              node = current_node.get(part)
  
              # If this is a path to a node we visited before, change into it. If it's an `id` field, it's already been
              # set to its original value.
              if node is not None:
                  current_node = node
                  continue
  
              # If this is a full path, copy the data.
              if len(key) == end:
                  # Omit null'ed fields.
                  if processed[key] is not None:
                      current_node[part] = processed[key]
                  continue
  
              # If the path is to a new array, start a new array, and change into it.
              if isinstance(key[end], IdValue):
                  new_node = []
              # If the path is to a new object, start a new object, and change into it.
              else:
                  new_node = OrderedDict()
  
              current_node[part] = new_node
              current_node = new_node
  
      return unflattened
docs: Unflattens a processed object into a JSON object.