# json-flatten
[![PyPI](https://img.shields.io/pypi/v/json-flatten.svg)](https://pypi.org/project/json-flatten/)
[![Changelog](https://img.shields.io/github/v/release/simonw/json-flatten?include_prereleases&label=changelog)](https://github.com/simonw/json-flatten/releases)
[![Tests](https://github.com/simonw/json-flatten/workflows/Test/badge.svg)](https://github.com/simonw/json-flatten/actions?query=workflow%3ATest)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/simonw/json-flatten/blob/main/LICENSE)
Python functions for flattening a JSON object to a single dictionary of pairs, and unflattening that dictionary back to a JSON object.
This can be useful if you need to represent a JSON object using a regular HTML form or transmit it as a set of query string parameters.
For example:
```pycon
>>> import json_flatten
>>> json_flatten.flatten({"foo": {"bar": [1, True, None]}})
{'foo.bar.[0]$int': '1', 'foo.bar.[1]$bool': 'True', 'foo.bar.[2]$none': 'None'}
>>> json_flatten.unflatten(_)
{'foo': {'bar': [1, True, None]}}
```
The top-level object passed to `flatten()` must be a dictionary.
## JSON flattening format
### Basic principles
1. Keys are constructed using dot notation to represent nesting.
2. Type information is preserved using `$type` suffixes.
3. List indices are represented using `[index]` notation.
4. Empty objects and lists have special representations.
### Nested objects
For nested objects, keys are constructed by joining the nested keys with dots.
Example:
<!-- [[[cog
import cog
import json
from json_flatten import flatten
example = {
"user": {
"name": "John",
"age": 30
}
}
cog.out("```json\n")
cog.out(json.dumps(example, indent=2))
cog.out("\n```\n")
cog.out("Flattened:\n```\n")
for key, value in flatten(example).items():
cog.out(f"{key}={value}\n")
cog.out("```\n")
]]] -->
```json
{
"user": {
"name": "John",
"age": 30
}
}
```
Flattened:
```
user.name=John
user.age$int=30
```
<!-- [[[end]]] -->
### Lists
List items are represented using `[index]` notation.
Example:
<!-- [[[cog
example = {
"fruits": ["apple", "banana", "cherry"]
}
cog.out("```json\n")
cog.out(json.dumps(example, indent=2))
cog.out("\n```\n")
cog.out("Flattened:\n```\n")
for key, value in flatten(example).items():
cog.out(f"{key}={value}\n")
cog.out("```\n")
]]] -->
```json
{
"fruits": [
"apple",
"banana",
"cherry"
]
}
```
Flattened:
```
fruits.[0]=apple
fruits.[1]=banana
fruits.[2]=cherry
```
<!-- [[[end]]] -->
### Nested lists
For nested lists, the index notation is repeated.
Example:
<!-- [[[cog
example = {
"matrix": [[1, 2], [3, 4]]
}
cog.out("```json\n")
cog.out(json.dumps(example))
cog.out("\n```\n")
cog.out("Flattened:\n```\n")
for key, value in flatten(example).items():
cog.out(f"{key}={value}\n")
cog.out("```\n")
]]] -->
```json
{"matrix": [[1, 2], [3, 4]]}
```
Flattened:
```
matrix.[0].[0]$int=1
matrix.[0].[1]$int=2
matrix.[1].[0]$int=3
matrix.[1].[1]$int=4
```
<!-- [[[end]]] -->
## Type preservation
Types are preserved using `$type` suffixes:
<!-- [[[cog
examples = (
("String", "", {"name": "Cleo"}),
("Integer", "$int", {"age": 30}),
("Float", "$float", {"price": 19.99}),
("Boolean", "$bool", {"active": True}),
("Null", "$none", {"data": None}),
("Empty object", "$empty", {"obj": {}}),
("Empty list", "$emptylist", {"list": []}),
)
cog.out("| Type | Suffix | Example |\n")
cog.out("|------|--------|---------|\n")
for type_, suffix, example in (examples):
key, value = list(flatten(example).items())[0]
suffix = f'`{suffix}`' if suffix else ''
cog.out(f"|{type_}|{suffix}|`{key}={value}`|\n")
]]] -->
| Type | Suffix | Example |
|------|--------|---------|
|String||`name=Cleo`|
|Integer|`$int`|`age$int=30`|
|Float|`$float`|`price$float=19.99`|
|Boolean|`$bool`|`active$bool=True`|
|Null|`$none`|`data$none=None`|
|Empty object|`$empty`|`obj$empty={}`|
|Empty list|`$emptylist`|`list$emptylist=[]`|
<!-- [[[end]]] -->
String values do not require a type suffix.
## Example
JSON:
<!-- [[[cog
example = {
"user": {
"name": "Alice",
"age": 28,
"hobbies": ["reading", "swimming"],
"address": {
"street": "123 Main St",
"city": "Anytown"
},
"active": True,
"salary": 50000.50,
"spouse": None
}
}
cog.out("```json\n")
cog.out(json.dumps(example, indent=2))
cog.out("\n```\n")
cog.out("\nFlattened:\n```\n")
for key, value in flatten(example).items():
cog.out(f"{key}={value}\n")
cog.out("```\n")
]]] -->
```json
{
"user": {
"name": "Alice",
"age": 28,
"hobbies": [
"reading",
"swimming"
],
"address": {
"street": "123 Main St",
"city": "Anytown"
},
"active": true,
"salary": 50000.5,
"spouse": null
}
}
```
Flattened:
```
user.name=Alice
user.age$int=28
user.hobbies.[0]=reading
user.hobbies.[1]=swimming
user.address.street=123 Main St
user.address.city=Anytown
user.active$bool=True
user.salary$float=50000.5
user.spouse$none=None
```
<!-- [[[end]]] -->
Raw data
{
"_id": null,
"home_page": "https://github.com/simonw/json-flatten",
"name": "json-flatten",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "Simon Willison",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/a1/06/e6a7046e71488a899a990206dc2426e8b9192ab7a341bb95a75ac1c88922/json_flatten-0.3.1.tar.gz",
"platform": null,
"description": "# json-flatten\n\n[![PyPI](https://img.shields.io/pypi/v/json-flatten.svg)](https://pypi.org/project/json-flatten/)\n[![Changelog](https://img.shields.io/github/v/release/simonw/json-flatten?include_prereleases&label=changelog)](https://github.com/simonw/json-flatten/releases)\n[![Tests](https://github.com/simonw/json-flatten/workflows/Test/badge.svg)](https://github.com/simonw/json-flatten/actions?query=workflow%3ATest)\n[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/simonw/json-flatten/blob/main/LICENSE)\n\n\nPython functions for flattening a JSON object to a single dictionary of pairs, and unflattening that dictionary back to a JSON object.\n\nThis can be useful if you need to represent a JSON object using a regular HTML form or transmit it as a set of query string parameters.\n\nFor example:\n\n```pycon\n>>> import json_flatten\n>>> json_flatten.flatten({\"foo\": {\"bar\": [1, True, None]}})\n{'foo.bar.[0]$int': '1', 'foo.bar.[1]$bool': 'True', 'foo.bar.[2]$none': 'None'}\n>>> json_flatten.unflatten(_)\n{'foo': {'bar': [1, True, None]}}\n```\n\nThe top-level object passed to `flatten()` must be a dictionary.\n\n## JSON flattening format\n\n### Basic principles\n\n1. Keys are constructed using dot notation to represent nesting.\n2. Type information is preserved using `$type` suffixes.\n3. List indices are represented using `[index]` notation.\n4. Empty objects and lists have special representations.\n\n### Nested objects\n\nFor nested objects, keys are constructed by joining the nested keys with dots.\n\nExample:\n\n<!-- [[[cog\nimport cog\nimport json\nfrom json_flatten import flatten\n\nexample = {\n \"user\": {\n \"name\": \"John\",\n \"age\": 30\n }\n}\n\ncog.out(\"```json\\n\")\ncog.out(json.dumps(example, indent=2))\ncog.out(\"\\n```\\n\")\ncog.out(\"Flattened:\\n```\\n\")\nfor key, value in flatten(example).items():\n cog.out(f\"{key}={value}\\n\")\ncog.out(\"```\\n\")\n]]] -->\n```json\n{\n \"user\": {\n \"name\": \"John\",\n \"age\": 30\n }\n}\n```\nFlattened:\n```\nuser.name=John\nuser.age$int=30\n```\n<!-- [[[end]]] -->\n\n### Lists\n\nList items are represented using `[index]` notation.\n\nExample:\n<!-- [[[cog\nexample = {\n \"fruits\": [\"apple\", \"banana\", \"cherry\"]\n}\n\ncog.out(\"```json\\n\")\ncog.out(json.dumps(example, indent=2))\ncog.out(\"\\n```\\n\")\ncog.out(\"Flattened:\\n```\\n\")\nfor key, value in flatten(example).items():\n cog.out(f\"{key}={value}\\n\")\ncog.out(\"```\\n\")\n]]] -->\n```json\n{\n \"fruits\": [\n \"apple\",\n \"banana\",\n \"cherry\"\n ]\n}\n```\nFlattened:\n```\nfruits.[0]=apple\nfruits.[1]=banana\nfruits.[2]=cherry\n```\n<!-- [[[end]]] -->\n\n### Nested lists\n\nFor nested lists, the index notation is repeated.\n\nExample:\n<!-- [[[cog\nexample = {\n \"matrix\": [[1, 2], [3, 4]]\n}\n\ncog.out(\"```json\\n\")\ncog.out(json.dumps(example))\ncog.out(\"\\n```\\n\")\ncog.out(\"Flattened:\\n```\\n\")\nfor key, value in flatten(example).items():\n cog.out(f\"{key}={value}\\n\")\ncog.out(\"```\\n\")\n]]] -->\n```json\n{\"matrix\": [[1, 2], [3, 4]]}\n```\nFlattened:\n```\nmatrix.[0].[0]$int=1\nmatrix.[0].[1]$int=2\nmatrix.[1].[0]$int=3\nmatrix.[1].[1]$int=4\n```\n<!-- [[[end]]] -->\n\n## Type preservation\n\nTypes are preserved using `$type` suffixes:\n\n<!-- [[[cog\nexamples = (\n (\"String\", \"\", {\"name\": \"Cleo\"}),\n (\"Integer\", \"$int\", {\"age\": 30}),\n (\"Float\", \"$float\", {\"price\": 19.99}),\n (\"Boolean\", \"$bool\", {\"active\": True}),\n (\"Null\", \"$none\", {\"data\": None}),\n (\"Empty object\", \"$empty\", {\"obj\": {}}),\n (\"Empty list\", \"$emptylist\", {\"list\": []}),\n)\ncog.out(\"| Type | Suffix | Example |\\n\")\ncog.out(\"|------|--------|---------|\\n\")\nfor type_, suffix, example in (examples):\n key, value = list(flatten(example).items())[0]\n suffix = f'`{suffix}`' if suffix else ''\n cog.out(f\"|{type_}|{suffix}|`{key}={value}`|\\n\")\n]]] -->\n| Type | Suffix | Example |\n|------|--------|---------|\n|String||`name=Cleo`|\n|Integer|`$int`|`age$int=30`|\n|Float|`$float`|`price$float=19.99`|\n|Boolean|`$bool`|`active$bool=True`|\n|Null|`$none`|`data$none=None`|\n|Empty object|`$empty`|`obj$empty={}`|\n|Empty list|`$emptylist`|`list$emptylist=[]`|\n<!-- [[[end]]] -->\n\nString values do not require a type suffix.\n\n## Example\n\nJSON:\n<!-- [[[cog\nexample = {\n \"user\": {\n \"name\": \"Alice\",\n \"age\": 28,\n \"hobbies\": [\"reading\", \"swimming\"],\n \"address\": {\n \"street\": \"123 Main St\",\n \"city\": \"Anytown\"\n },\n \"active\": True,\n \"salary\": 50000.50,\n \"spouse\": None\n }\n}\n\ncog.out(\"```json\\n\")\ncog.out(json.dumps(example, indent=2))\ncog.out(\"\\n```\\n\")\ncog.out(\"\\nFlattened:\\n```\\n\")\nfor key, value in flatten(example).items():\n cog.out(f\"{key}={value}\\n\")\ncog.out(\"```\\n\")\n]]] -->\n```json\n{\n \"user\": {\n \"name\": \"Alice\",\n \"age\": 28,\n \"hobbies\": [\n \"reading\",\n \"swimming\"\n ],\n \"address\": {\n \"street\": \"123 Main St\",\n \"city\": \"Anytown\"\n },\n \"active\": true,\n \"salary\": 50000.5,\n \"spouse\": null\n }\n}\n```\n\nFlattened:\n```\nuser.name=Alice\nuser.age$int=28\nuser.hobbies.[0]=reading\nuser.hobbies.[1]=swimming\nuser.address.street=123 Main St\nuser.address.city=Anytown\nuser.active$bool=True\nuser.salary$float=50000.5\nuser.spouse$none=None\n```\n<!-- [[[end]]] -->\n",
"bugtrack_url": null,
"license": "Apache License, Version 2.0",
"summary": "Python functions for flattening a JSON object to a single dictionary of pairs, and unflattening that dictionary back to a JSON object",
"version": "0.3.1",
"project_urls": {
"CI": "https://github.com/simonw/json-flatten/actions",
"Changelog": "https://github.com/simonw/json-flatten/releases",
"Homepage": "https://github.com/simonw/json-flatten",
"Issues": "https://github.com/simonw/json-flatten/issues"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "9bed75de9521770184c783ec0d4d75c0bb00f99ac7a21bca48adf9df596483c3",
"md5": "b5f7dca5494635a1dc42cc217808933a",
"sha256": "26470dbe9d6d7eb1b7f69c59ba2ade9d52608a76b8443e4654f3adb9c78c1c3e"
},
"downloads": -1,
"filename": "json_flatten-0.3.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "b5f7dca5494635a1dc42cc217808933a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 8473,
"upload_time": "2024-09-07T04:16:01",
"upload_time_iso_8601": "2024-09-07T04:16:01.799899Z",
"url": "https://files.pythonhosted.org/packages/9b/ed/75de9521770184c783ec0d4d75c0bb00f99ac7a21bca48adf9df596483c3/json_flatten-0.3.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a106e6a7046e71488a899a990206dc2426e8b9192ab7a341bb95a75ac1c88922",
"md5": "3dee06b8e645d081269ed76fe501cd71",
"sha256": "70e813acf431b1ab7e9eb7b98f5733d307d6b9d27b553a344904b9c8eafdad3a"
},
"downloads": -1,
"filename": "json_flatten-0.3.1.tar.gz",
"has_sig": false,
"md5_digest": "3dee06b8e645d081269ed76fe501cd71",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8303,
"upload_time": "2024-09-07T04:16:02",
"upload_time_iso_8601": "2024-09-07T04:16:02.978164Z",
"url": "https://files.pythonhosted.org/packages/a1/06/e6a7046e71488a899a990206dc2426e8b9192ab7a341bb95a75ac1c88922/json_flatten-0.3.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-07 04:16:02",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "simonw",
"github_project": "json-flatten",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "json-flatten"
}