Unflattens a processed object into a JSON object.

def unflatten(processed, merge_rules):
    """
    Unflattens a processed object into a JSON object.
    """
    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