Json_To_Many is a zero-dependency Python library for converting JSON data into multiple output formats — Markdown, XML, CSV, and more. It is built for developers who need format conversion as part of a codebase, script, or CI pipeline — not as a one-off manual task.
Every conversion returns a typed ConversionResult so callers never need to parse raw output strings. The package ships py.typed and full annotations, so mypy and pyright work without any extra configuration.
- Generating Markdown documentation from API responses or config data
- Producing XML output for legacy system integration
- Exporting structured data as CSV for downstream tooling
- Automating format conversion in CI pipelines
- Zero mandatory dependencies —
pip install json_to_manybrings nothing else with it - Typed by default — full annotations,
py.typedmarker, works with strict mypy/pyright - Structured return type —
ConversionResult.data,.format,.stats— no string parsing - Composable — plays cleanly with
jq, shell pipes, and GitHub Actions
| Format | Options |
|---|---|
| Markdown | title, heading_offset, max_heading_level, bullet_lists, table_for_lists, frontmatter, code_block_keys |
| XML | root_element, item_element, pretty_print |
| CSV | delimiter, quotechar, include_header, columns |
Install Json_To_Many using pip:
pip install json_to_manyOr, if you prefer using uv:
uv add json_to_manyfrom json_to_many import convert
# Convert JSON string to Markdown and save to 'output.md'
json_string = '{"title": "Sample Document", "content": "This is a sample."}'
convert(json_string, 'markdown', output_file='output.md')
# Convert JSON file to XML — always returns a ConversionResult
result = convert('data.json', 'xml')
print(result.data) # the XML string
print(result.stats) # ConversionStats(rows=..., fields=...)From a JSON File:
from json_to_many import convert
# Convert JSON file to Markdown and save to 'output.md'
convert('data.json', 'markdown', output_file='output.md')From a JSON String:
from json_to_many import convert
json_string = '{"title": "Sample Document", "content": "This is a sample."}'
result = convert(json_string, 'markdown')
print(result.data)Sample Output:
# title
Sample Document
# content
This is a sample.The Markdown converter accepts optional keyword arguments to customise its output. All options are passed directly to convert().
| Option | Type | Default | Description |
|---|---|---|---|
title |
str |
None |
Prepends # {title} at the top of the document |
heading_offset |
int |
0 |
Shifts all heading levels by this amount (e.g. 1 makes top-level keys H2) |
max_heading_level |
int |
6 |
Keys deeper than this render as **bold** instead of headings |
bullet_lists |
bool |
True |
Renders lists of primitives as - item bullet points |
Example:
from json_to_many import convert
data = {
"Project": {
"Name": "MyApp",
"Tech": ["Python", "FastAPI"],
}
}
# Shift headings down one level and add a document title
result = convert(data, "markdown",
title="Project Report",
heading_offset=1,
bullet_lists=True)
print(result.data)# Project Report
## Project
### Name
MyApp
### Tech
- Python
- FastAPI| Option | Type | Default | Description |
|---|---|---|---|
table_for_lists |
bool |
False |
Renders a list of dicts with common keys as a GFM pipe table |
Example:
data = {
"Users": [
{"name": "Alice", "role": "admin"},
{"name": "Bob", "role": "user"},
]
}
result = convert(data, "markdown", table_for_lists=True)
md = result.data# Users
| name | role |
| --- | --- |
| Alice | admin |
| Bob | user || Option | Type | Default | Description |
|---|---|---|---|
frontmatter |
dict |
None |
Emits a YAML frontmatter block (for static site generators, Obsidian, etc.) |
Supports str, int, float, bool, and None values. No external dependencies required.
Example:
result = convert(data, "markdown",
frontmatter={"title": "API Docs", "date": "2025-02-21", "draft": False})
md = result.data---
title: API Docs
date: 2025-02-21
draft: false
---
...content...| Option | Type | Default | Description |
|---|---|---|---|
code_block_keys |
list |
[] |
Values for these keys are rendered as fenced code blocks |
Example:
data = {
"endpoint": "/users",
"example_request": '{"filter": "active"}',
}
result = convert(data, "markdown", code_block_keys=["example_request"])
md = result.data# endpoint
/users
# example_request
\`\`\`example_request
{"filter": "active"}
\`\`\`From a Python Dictionary:
from json_to_many import convert
json_data = {
"note": {
"to": "Alice",
"from": "Bob",
"message": "Hello, Alice!"
}
}
# Convert JSON data to XML and save to 'note.xml'
convert(json_data, 'xml', output_file='note.xml')
# Get the converted data
result = convert(json_data, 'xml')
print(result.data)Sample Output:
<root><note><to>Alice</to><from>Bob</from><message>Hello, Alice!</message></note></root>| Option | Type | Default | Description |
|---|---|---|---|
root_element |
str |
"root" |
Name of the top-level XML element |
item_element |
str | None |
None |
Wraps each list item in a named element (e.g. "item") |
pretty_print |
bool |
False |
Indents the XML output for readability |
Example:
data = [{"id": "1", "name": "Alice"}, {"id": "2", "name": "Bob"}]
result = convert(data, "xml",
root_element="users",
item_element="user",
pretty_print=True)
print(result.data)<users>
<user>
<id>1</id>
<name>Alice</name>
</user>
<user>
<id>2</id>
<name>Bob</name>
</user>
</users>From a Python List of Dictionaries:
from json_to_many import convert
json_data = [
{"name": "Alice", "age": 30, "city": "New York"},
{"name": "Bob", "age": 25, "city": "Los Angeles"}
]
# Convert JSON data to CSV and save to 'data.csv'
convert(json_data, 'csv', output_file='data.csv')Get Converted CSV Data Without Saving:
result = convert(json_data, 'csv')
print(result.data)Sample Output:
name,age,city
Alice,30,New York
Bob,25,Los AngelesNote: The CSV converter automatically flattens nested JSON structures using dot-notation keys (e.g. address.city).
| Option | Type | Default | Description |
|---|---|---|---|
delimiter |
str |
"," |
Field separator character |
quotechar |
str |
'"' |
Character used to quote fields containing the delimiter |
include_header |
bool |
True |
Whether to include the header row |
columns |
list[str] | None |
None |
Explicit column list; controls order and limits output to these fields |
Example:
data = [
{"name": "Alice", "role": "admin", "joined": "2024-01-01"},
{"name": "Bob", "role": "user", "joined": "2024-03-15"},
]
# Semicolon-separated, specific columns only
result = convert(data, "csv",
delimiter=";",
columns=["name", "role"])
print(result.data)name;role
Alice;admin
Bob;userThe examples directory contains sample scripts and data to help you get started.
- JSON to Markdown Conversion: json_to_markdown_example.py
- JSON to XML Conversion: json_to_xml_example.py
- JSON to CSV Conversion: json_to_csv_example.py
-
Clone the Repository:
git clone https://github.com/ananthanandanan/Json_To_Many.git cd Json_To_Many/examples -
Install Dependencies (for development):
uv sync
Or install the package directly:
pip install json_to_many
-
Run an Example Script:
uv run python json_to_markdown_example.py # or if installed globally: python json_to_markdown_example.py
The project uses uv for dependency management and packaging, and Ruff for linting and code style enforcement.
-
Fork the Repository:
Click the "Fork" button at the top right corner of the repository page.
-
Clone Your Fork:
git clone https://github.com/ananthanandanan/Json_To_Many.git cd Json_To_Many -
Install Dependencies:
uv sync
-
Run Tests:
uv run pytest
-
Check Code Quality with Ruff:
uv run ruff check . -
Build the Package:
uv build
- Code Style: Follow PEP 8 guidelines. Use Ruff for linting and code style enforcement.
- Testing: Write unit tests for new features and bug fixes.
- Documentation: Update documentation and examples to reflect changes.
Maintainers: See RELEASING.md for the full release process (version bump, tagging, GitHub Release, and PyPI publish).
Contributions are welcome! Here's how you can help:
- Report Bugs: If you find a bug, please report it by opening an issue.
- Suggest Features: Have an idea for a new feature? Feel free to share it.
- Submit Pull Requests: If you'd like to fix a bug or implement a feature, you're welcome to contribute code.
-
Create an Issue:
Before starting work on a feature or bug fix, please create an issue to discuss it.
-
Branch Naming:
Use descriptive branch names, e.g.,
feature/json-to-yamlorbugfix/fix-xml-output. -
Pull Requests:
- Include a clear description of the changes.
- Reference the issue number.
- Ensure all tests pass and code quality checks are successful.
-
Code Quality:
- Run
uv run pytestto ensure all tests pass. - Run
uv run ruff check .to ensure code style compliance.
- Run
This project is licensed under the MIT License - see the LICENSE file for details.
For questions or support, please open an issue or contact K N Anantha nandanan.