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) usingkey.split(separator). - Safe mode (
safe=True): The function callsdecode_safe_key(key, separator)fromjsoncsv/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:
- Groups entries by their first path element.
- 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 Pythonlist(array). Otherwise, they become adict. - 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 theexpandphase.decode_safe_key: Reverses the escaping duringrestore, 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
restorefunction injsoncsv/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_keyinjsoncsv/utils.py(lines 21‑41). - The
from_leafhelper (lines 61‑90) recursively assembles structures, automatically detecting arrays usingis_array_index. - Empty keys are treated as root-level assignments, enabling reconstruction of top-level scalar values.
- The
safeparameter 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →