This is a easy to use library for walking through json data.
Project description
JsonWalker
Allows simple, quick, and easy parsing of nasty nested JSON through a fluent object-oriented tool to avoid hours of pain
JsonWalker's goal is to allow users to specify a path through nested JSON using a chainable, discoverable API, and get the items at each match in the JSON. The library uses generators to efficiently traverse large data structures.
Installation
JsonWalker is a pip installable package. It is a public package, and will thus not need any special permissions to install.
Command Line Installation
To install from the command line, simply do pip install JsonWalker.
Use in other pip packages
As this is a public package, it can be added to the required packages of any pip installable packages and will be installed automatically when those are installed in other projects.
Usage
To use this in a project, install using one of the installation methods shown above.
Import the JsonPath class into your file: from JsonWalker.walk import JsonPath
As the walk command makes a generator, it can be used in multiple ways.
{
'users': [
{
'name': 'samantha',
'points': 2394729
},
{
'name': 'john',
'points': 2392987
}
]
}
Use in a for loop
path = JsonPath().key("users").listAll().key("name")
for name in path.walk(data):
...
Use outside of a for loop
path = JsonPath().key("users").listAll().key("name")
name = next(path.walk(data))
The next function is a Python function that gets the "next" value in the generator, and can be called multiple times in a row if desired.
Quick Start Examples
Here are some practical examples to get you started quickly:
Example 1: Simple Key Access with Defaults
from JsonWalker.walk import JsonPath
# Sample data with missing keys
data = {
"key1": [
{
"key2": 100
},
{} # key2 is missing here, so contextOfKey1 will be blank, and the default value for key2 will be used
]
}
path = JsonPath().key("key1").listAll().addContext().key("key2", default=-1)
for contextOfKey1, key2 in path.walk(data):
print(f"contextOfKey1: {contextOfKey1}, valueOfKey2: {key2}")
Output:
contextOfKey1: {'key2': 100}, valueOfKey2: 100
contextOfKey1: {}, valueOfKey2: -1
Example 2: Multi-Value Return
from JsonWalker.walk import JsonPath
# Sample data
data = {
"key1": {
"key2": {
"itemA": "hello",
"itemB": "world",
"itemC": "I use Arch, by the way" # Nobody wants this
}
}
}
path = JsonPath().key("key1").addContext().key("key2").multi(
JsonPath().key("itemA"),
JsonPath().key("itemB")
)
# If you removed .addContext(), key1Context would not be part of this line
# and everything else would stay the same
for key1Context, itemA, itemB in path.walk(data):
print(f"{itemA} {itemB}!")
print(key1Context)
Output:
hello world!
{'key2': {'itemA': 'hello', 'itemB': 'world', 'itemC': 'I use Arch, by the way'}}
Example 3: Dictionary Iteration
from JsonWalker.walk import JsonPath
# Sample data
data = {
"key1": {
"key2": "value2",
"key3": "value3",
"key4": "value4"
}
}
path = JsonPath().key("key1").keyContextAndValue()
for key, value in path.walk(data):
print(f"{key} -- {value}")
Output:
key2 -- value2
key3 -- value3
key4 -- value4
Understanding Context
Context is one of JsonWalker's most powerful features. It allows you to collect and preserve intermediate values as you traverse through nested JSON structures.
How Context Works
- Context is a list that accumulates values as you traverse the JSON
- When you reach the end of a path, you get back either:
- Just the final value (if no context was collected)
- A list containing
[context_values..., final_value](if context was collected)
- Context is particularly useful when you need to know "where you came from" or want to collect multiple related values
Context Collection Methods
.addContext()- Adds the current value to the context before continuing.keyContextAndValue()- When iterating through dictionary items, adds just the key's string to the context, rather than the whole dictionary object.multi()- Collects values from multiple sub-paths and includes them in the result
Simple Context Example
from JsonWalker.walk import JsonPath
data = {
"users": [
{"name": "John", "age": 30},
{"name": "Jane", "age": 25}
]
}
# Without context - just get names
path = JsonPath().key("users").listAll().key("name")
for name in path.walk(data):
print(name)
print()
# With context - get both user object and name
path = JsonPath().key("users").listAll().addContext().key("name")
for user, name in path.walk(data):
print(f"{name} has age {user['age']}")
Output
John
Jane
John has age 30
Jane has age 25
API Reference
JsonWalker uses a fluent, chainable API that makes queries self-documenting and discoverable through IDE autocompletion.
Core
| Core | Description |
|---|---|
JsonPath() |
Start a new JSON path query chain |
.walk(data) |
Execute the path query on JSON data as a Generator (gets all the data WHEN you want it, making walk lightning fast) |
Path Building Methods
| Method | Description | Example |
|---|---|---|
.key(name, default=None) |
Access dictionary by key with optional default if the key is not found | .key("users") |
.listIndex(idx) |
Access list by specific index (supports negative indices) | .listIndex(0) or .listIndex(-1) |
.listSlice(start, end) |
Access range of list items | .listSlice(1, 5) |
.listAll() |
Access all items in a list | .listAll() |
.keyContextAndValue() |
Iterate through key-value pairs of dictionaries, adding keys to context | .keyContextAndValue() |
.addContext() |
Add the current value to the context before continuing | .addContext() |
.multi(*paths) |
Create diverging paths from the current context, returning all possible combinations of values | .multi(path1, path2) |
Complete Examples
All examples below include the necessary imports and sample data so you can copy and run them immediately.
Simple Key Access
from JsonWalker.walk import JsonPath
# Sample data
data = {
"user": {
"name": "John",
"age": 30
}
}
# Access user's name
path = JsonPath().key("user").key("name")
for name in path.walk(data):
print(name)
Output
John
List Iteration with Context
from JsonWalker.walk import JsonPath
# Sample data
data = {
"users": [
{"name": "John", "age": 30},
{"name": "Jane", "age": 25}
]
}
# Iterate through all users, keeping user object as context
path = JsonPath().key("users").listAll().addContext().key("name", default="Unknown")
for user, name in path.walk(data):
print(f"{name} is part of the user dictionary - {user}")
Output:
John is part of the user dictionary - {'name': 'John', 'age': 30}
Jane is part of the user dictionary - {'name': 'Jane', 'age': 25}
Multi-Value Return
from JsonWalker.walk import JsonPath
# Sample data
data = {
"users": [
{
"profile": {
"firstName": "John",
"lastName": "Doe"
}
},
{
"profile": {
"firstName": "Kaladin",
"lastName": "Stormblessed"
}
}
]
}
# Get both first and last name in one query
path = JsonPath().key("users").listAll().key("profile").multi(
JsonPath().key("firstName"),
JsonPath().key("lastName")
)
for firstName, lastName in path.walk(data):
print(f"{firstName} {lastName}")
Output
John Doe
Kaladin Stormblessed
Dictionary Iteration with Context
from JsonWalker.walk import JsonPath
# Sample data
data = {
"scores": {
"math": 95,
"science": 87,
"english": 92
}
}
# Iterate through all key-value pairs
path = JsonPath().key("scores").keyContextAndValue()
for subject, score in path.walk(data):
print(f"{subject}: {score}")
Output:
math: 95
science: 87
english: 92
Range and Slice Operations
from JsonWalker.walk import JsonPath
# Sample data
data = {
"numbers": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}
# Get numbers from index 2 to 5 (exclusive)
list1 = []
path = JsonPath().key("numbers").listSlice(2, 6)
for num in path.walk(data):
list1.append(num)
print(list1)
# Get the last 3 numbers
list2 = []
path = JsonPath().key("numbers").listSlice(-3, None)
for num in path.walk(data):
list2.append(num)
print(list2)
Output
[2, 3, 4, 5]
[7, 8, 9]
Complex Nested Data with Added Context
from JsonWalker.walk import JsonPath
# Sample data
data = {
"departments": [
{
"name": "Engineering",
"employees": [
{"name": "Alice", "skills": ["Python", "JavaScript"]},
{"name": "Bob", "skills": ["Java", "C++"]}
]
},
{
"name": "Marketing",
"employees": [
{"name": "Charlie", "skills": ["SEO", "Analytics"]}
]
}
]
}
# Get all employee names with their department and skills
# This demonstrates nested context collection
path = (JsonPath()
.key("departments")
.listAll()
.addContext() # Keep department info in context
.key("employees")
.listAll()
.multi(
JsonPath().key("name"),
JsonPath().key("skills").listAll()
)
)
# The whole department dictionary is stored as context, which is why we can access its 'name' key
for dept, name, skill in path.walk(data):
print(f"{name} from {dept['name']} knows {skill}")
Output:
Alice from Engineering knows Python
Alice from Engineering knows JavaScript
Bob from Engineering knows Java
Bob from Engineering knows C++
Charlie from Marketing knows SEO
Charlie from Marketing knows Analytics
Real-World Example: Processing Complex API Response
from JsonWalker.walk import JsonPath
# Sample data (complex nested structure like from an API)
apiResponse = {
"persons": [
{
"id": "123",
"names": [
{
"nameForms": [
{
"parts": [
{
"fields": [
{
"values": [
{"labelId": "PR_GIVEN", "value": "John"}
]
}
]
}
]
}
]
}
],
"links": {
"persona": {
"href": "https://example.com/personas/456"
}
}
}
]
}
# Extract person info with complex nested structure
person_path = JsonPath().key("persons").listAll().addContext().multi(
JsonPath().key("id"),
JsonPath().key("links").key("persona").key("href", default="")
)
for person, person_id, href in person_path.walk(apiResponse):
print(f"Processing person {person_id} with href: {href}")
# Get label IDs from deeply nested structure
label_path = (JsonPath()
.key("names")
.listAll()
.key("nameForms")
.listAll()
.key("parts")
.listAll()
.key("fields")
.listAll()
.key("values")
.listAll()
.key("labelId", default="")
)
for labelID in label_path.walk(person):
if 'PR' in labelID and 'FTHR' not in labelID and 'MTHR' not in labelID:
print(f"Found person {person_id} with label {labelID}")
Output
Found person 123 with label PR_GIVEN
Using Single Values with next()
from JsonWalker.walk import JsonPath
# Sample data
data = {
"users": [
{"name": "John", "age": 30},
{"name": "Jane", "age": 25}
]
}
# Get just the first user's name
path = JsonPath().key("users").listIndex(0).key("name")
result = next(path.walk(data))
print(f"First user's name: {result}")
# Get the last user's age
path = JsonPath().key("users").listIndex(-1).key("age")
result = next(path.walk(data))
print(f"Last user's age: {result}")
Output:
First user's name: John
Last user's age: 25
Handling Missing Keys with Defaults
from JsonWalker.walk import JsonPath
# Sample data with missing fields
data = {
"users": [
{"name": "John", "age": 30},
{"name": "Jane"}, # Missing age
{"age": 40} # Missing name
]
}
# Access with defaults for missing keys
path = JsonPath().key("users").listAll().addContext().multi(
JsonPath().key("name", default="unknown_name"),
JsonPath().key("age", default=-1)
)
for user, name, age in path.walk(data):
print(f"{name} is {age} years old")
Output:
John is 30 years old
Jane is -1 years old
unknown_name is 40 years old
Real World Example: Two different paths
As you can see in the data below, the subcategory of electronics contains multiple sections, which have the items we are looking for. On the other hand, the subcategory of books does NOT have any sections, and just contains the books themselves. This is a great example of how real world data can be messy, but consistent. On the bright side, JsonWalker can handle this with two different paths.
# Sample data with nested categories
data = {
"categories": {
"electronics": {
"computers": {
"laptops": ["MacBook", "ThinkPad", "Dell XPS"],
"desktops": ["iMac", "HP Pavilion"]
},
"phones": {
"smartphones": ["iPhone", "Samsung Galaxy"]
}
},
"books": ["The Way of Kings", "To Kill a Mockingbird", "Dragonsbane", "Number the Stars"]
}
}
path = JsonPath().key('categories').key('electronics').keyContextAndValue().keyContextAndValue().listAll()
for subcategory, section, item in path.walk(data):
print(item)
path = JsonPath().key('categories').key('books').listAll()
for item in path.walk(data):
print(item)
Output:
MacBook
ThinkPad
Dell XPS
iMac
HP Pavilion
iPhone
Samsung Galaxy
The Way of Kings
To Kill a Mockingbird
Dragonsbane
Number the Stars
Key Features
- Generator-based: Efficient memory usage for large datasets
- Chainable API: Build complex queries step by step
- Context preservation: Keep intermediate values during traversal with multiple context collection strategies
- Type-safe defaults: Specify fallback values with proper types
- Multi-value queries: Extract multiple values in a single traversal
- Flexible indexing: Support for positive/negative indices and slicing
- Dictionary iteration: Built-in support for key-value pair traversal with context
Context System Benefits
- Relationship Preservation: Keep track of parent-child relationships in nested data
- Multi-level Data Collection: Gather information from different nesting levels in one pass
- Flexible Output: Choose exactly what information you need from each level
- Memory Efficient: Context is only collected when explicitly requested
Best Practices
- Use meaningful variable names: The fluent API makes it easy to create readable code
- Chain operations logically: Group related operations together
- Leverage context strategically: Use
.addContext()when you need parent information,.keyContextAndValue()for dictionary keys - Provide defaults: Use the
defaultparameter to handle missing keys gracefully - Break complex queries: Split very long chains into intermediate variables for readability
- Understand context flow: Remember that context accumulates - each
.addContext()or.keyContextAndValue()adds to your result tuple
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jsonwalker-1.0.17.tar.gz.
File metadata
- Download URL: jsonwalker-1.0.17.tar.gz
- Upload date:
- Size: 13.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd6f9d96466abb61b3a765305e6bd8f110328bf31a7c0999c997e0a39ae8740c
|
|
| MD5 |
aa74cf3a1b52f45a2e5d924aeac67f7c
|
|
| BLAKE2b-256 |
f5cb43d20b7ff462c1a1d1d755c2d09f69262042be43c891671b2139c8f3ab30
|
File details
Details for the file jsonwalker-1.0.17-py3-none-any.whl.
File metadata
- Download URL: jsonwalker-1.0.17-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eed5970fdf0514445098a2d91f41ba76a6516e6755c1a08a9f48cec48387a2e5
|
|
| MD5 |
314a39a4edaecfa48b54286fae39fc8c
|
|
| BLAKE2b-256 |
4361d106b540b5e2e1bc331f590d5cdaf2276f96662410b035726cd6f2109450
|