json-flatten


Namejson-flatten JSON
Version 0.3.1 PyPI version JSON
download
home_pagehttps://github.com/simonw/json-flatten
SummaryPython functions for flattening a JSON object to a single dictionary of pairs, and unflattening that dictionary back to a JSON object
upload_time2024-09-07 04:16:02
maintainerNone
docs_urlNone
authorSimon Willison
requires_pythonNone
licenseApache License, Version 2.0
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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"
}
        
Elapsed time: 1.03556s