How the restore Function in jsontool.py Reconstructs JSON Objects

The restore function in jsoncsv/jsontool.py reverses the flattening process by parsing dot-notated keys into hierarchical path components and recursively rebuilding nested dictionaries and lists.

The jsoncsv library provides bidirectional conversion between nested JSON objects and flat, CSV-friendly dictionaries. While expand flattens structures into dot-separated keys, the restore function performs the inverse operation, reconstructing the original JSON hierarchy from these flattened mappings. This reconstruction logic handles complex edge cases including escaped separators, empty root keys, and automatic array detection.

How restore Reconstructs JSON Step-by-Step

The restore function (defined in jsoncsv/jsontool.py lines 108‑122) operates in three distinct phases to convert a flattened dictionary back into its original nested structure.

Step 1: Parsing Keys into Path Components

For each entry in the flattened dictionary, restore converts the string key back into a list of path components. The method of parsing depends on the safe parameter:

  • Standard mode (safe=False): The key is split on the separator (. by default) using key.split(separator).
  • Safe mode (safe=True): The function calls decode_safe_key(key, separator) from jsoncsv/utils.py (lines 21‑41) to properly handle escaped separators and backslashes that appear within actual key names.

An empty key ("") represents the root level of the object, resulting in an empty path list [].

Step 2: Building the Leaf Specifications

After parsing, restore constructs a list of tuples called leafs, where each tuple contains (path_list, value). This format mirrors the output structure used by gen_leaf during the expand operation, creating a consistent internal representation for the reconstruction pipeline.

Step 3: Recursive Hierarchy Assembly with from_leaf

The core reconstruction occurs in the from_leaf helper function (lines 61‑90 of jsoncsv/jsontool.py). This recursive function:

  1. Groups entries by their first path element.
  2. Determines container type: If all first-level keys form a consecutive integer sequence (verified by is_array_index), the children are sorted and assembled into a Python list (array). Otherwise, they become a dict.
  3. Recurses on remaining path components until reaching leaf values.

The resulting Python object (origin) reflects the original nested JSON structure and is returned to the caller.

Handling Safe Separators and Escaped Characters

When working with JSON objects that contain the separator character within key names (e.g., a key named "a.b"), the standard splitting algorithm would fail. The safe parameter enables proper round-tripping through encoding functions in jsoncsv/utils.py:

  • encode_safe_key: Escapes literal dots and backslashes during the expand phase.
  • decode_safe_key: Reverses the escaping during restore, ensuring keys like "a.b" remain intact rather than being split into ["a", "b"].

This mechanism is essential for lossless conversion when property names contain characters that match the separator.

Practical Code Examples

Basic Round-Trip Reconstruction

This example demonstrates the complete workflow from nested JSON to flattened dictionary and back:

from jsoncsv.jsontool import expand, restore

original = {
    "user": {"id": 1, "name": "Alice"},
    "items": [{"sku": "A1"}, {"sku": "B2"}],
}

flat = expand(original)          

# {'user.id': 1, 'user.name': 'Alice', 'items.0.sku': 'A1', 'items.1.sku': 'B2'}

reconstructed = restore(flat)    

# {'user': {'id': 1, 'name': 'Alice'}, 'items': [{'sku': 'A1'}, {'sku': 'B2'}]}

assert original == reconstructed

Safe Mode with Dots in Keys

When your JSON contains literal dots in property names, use safe=True to prevent misinterpretation:

from jsoncsv.jsontool import expand, restore

data = {"a.b": {"c": 5}}        # Key contains a literal dot

flat = expand(data, separator=".", safe=True)   # Key becomes "\.a\.b.c"

restored = restore(flat, separator=".", safe=True)
assert restored == data

Custom Separator Support

You can specify alternative separators to avoid conflicts with your data:

sep = "/"
flat = {"root/child": 42}
restored = restore(flat, separator=sep)

# Result: {'root': {'child': 42}}

Summary

  • The restore function in jsoncsv/jsontool.py (lines 108‑122) reconstructs nested JSON by reversing the flattening process.
  • Path parsing supports both simple string splitting and safe decoding via decode_safe_key in jsoncsv/utils.py (lines 21‑41).
  • The from_leaf helper (lines 61‑90) recursively assembles structures, automatically detecting arrays using is_array_index.
  • Empty keys are treated as root-level assignments, enabling reconstruction of top-level scalar values.
  • The safe parameter ensures lossless round-tripping when key names contain separator characters.

Frequently Asked Questions

What is the difference between expand and restore in jsoncsv?

expand flattens nested JSON objects into single-level dictionaries with dot-separated keys, while restore performs the inverse operation by parsing those keys back into hierarchical structures. According to the jsoncsv source code, restore uses the from_leaf recursive function to rebuild lists and dictionaries from the flattened representation.

How does restore handle JSON arrays?

The restore function detects arrays by checking if all first-level keys in a group form a consecutive integer sequence using the is_array_index helper. When this condition is met, from_leaf sorts the children by their integer indices and returns them as a Python list rather than a dictionary, accurately reconstructing the original array structure.

What is the safe parameter in restore used for?

The safe parameter controls how keys containing literal separator characters are handled. When safe=True, restore calls decode_safe_key from jsoncsv/utils.py to properly interpret escaped separators and backslashes. This prevents keys like "user.name" from being split into ["user", "name"] when the dot is actually part of the property name rather than a path delimiter.

Where is the core restoration logic implemented?

The primary restoration logic resides in jsoncsv/jsontool.py. The restore function itself occupies lines 108‑122, while the recursive reconstruction engine from_leaf is implemented in lines 61‑90. Key parsing utilities for safe mode are located in jsoncsv/utils.py (lines 21‑41).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →