Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

539 Commits

Repository files navigation

json2xml hero

json2xml

https://static.pepy.tech/personalized-badge/json2xml?period=total&units=international_system&left_color=blue&right_color=orange&left_text=Downloads

Documentation Statushttps://codecov.io/gh/vinitkumar/json2xml/branch/master/graph/badge.svg?token=Yt2h55eTL2

json2xml is a Python library and CLI for converting JSON data into XML. It is designed for teams that need predictable XML output, Python-first ergonomics, and a faster native path when conversion speed matters.

Documentation: https://json2xml.readthedocs.io.

The library was initially dependent on the dict2xml project, but it has now been integrated into json2xml itself. This has led to cleaner code, the addition of types and tests, and overall improved performance.

Looking for a Go version? Check out json2xml-go, a Go port of this library with identical features and a native CLI tool.

Why json2xml?

Use json2xml when you need:

  • A Python library for turning dictionaries, strings, files, or API responses into XML
  • A command-line tool for quick JSON-to-XML conversion from scripts and terminals
  • Optional Rust acceleration with automatic fallback to the pure Python implementation
  • XPath 3.1 compatible output when standards-friendly XML is required
  • A small, focused project with tests, docs, benchmarks, and multiple native implementation experiments

Quick Start

Install the Python package:

pip install json2xml

Use it from Python:

fromjson2xmlimportjson2xmlfromjson2xml.utilsimportreadfromstringdata=readfromstring('{"name": "Ada", "language": "Python"}')
print(json2xml.Json2xml(data).to_xml())

Use it from the terminal:

json2xml-py -s '{"name": "Ada", "language": "Python"}'

Install the accelerated path:

pip install json2xml[fast]

Real-world Examples

Convert a JSON API response in Python when another system expects XML:

fromjson2xmlimportjson2xmlapi_response= {"user": {"id": 7, "name": "Ada"}, "active": True}
print(json2xml.Json2xml(api_response, pretty=False).to_xml().decode("utf-8"))

Output:

<?xml version="1.0" encoding="UTF-8" ?><all><usertype="dict"><idtype="int">7</id><nametype="str">Ada</name></user><activetype="bool">true</active></all>

Convert a local JSON export from the shell:

cat > orders.json <<'JSON'{"orders":[{"id":"A100","total":19.99},{"id":"A101","total":5.5}]}JSONjson2xml-py --no-pretty --no-type orders.json

Output:

<?xml version="1.0" encoding="UTF-8" ?><all><orders><item><id>A100</id><total>19.99</total></item><item><id>A101</id><total>5.5</total></item></orders></all>

Convert stdin in a shell pipeline:

printf '%s\n' '{"event":"deploy","status":"ok"}' | json2xml-py --no-pretty --no-type -

Output:

<?xml version="1.0" encoding="UTF-8" ?><all><event>deploy</event><status>ok</status></all>

Performance Snapshot

The optional Rust extension is the fastest path for Python callers because it avoids process startup overhead and falls back to pure Python when a feature is not supported natively.

Test CasePure PythonRust ExtensionSpeedup
Small JSON (47 bytes)31.49µs0.55µs56.8x
Medium JSON (3.2 KB)1.69ms16.15µs105.0x
Large JSON (32 KB)17.97ms168.21µs106.8x
Very Large JSON (323 KB)183.33ms1.42ms129.0x

See BENCHMARKS.md for the full Python, Rust, Go, and Zig comparison.

Project Roadmap

The next phase of json2xml is focused on making the project easier to adopt, benchmark, and contribute to:

  • Improve examples for common API, file, and CLI workflows
  • Add clearer contribution paths for docs, CLI polish, and benchmark coverage
  • Keep comparing Python, Rust, Go, and Zig implementations with reproducible benchmarks
  • Continue hardening the Rust extension fallback behavior across platforms

See ROADMAP.md for more detail.

Architecture Diagram

./diagram.png

Installation

As a Library

pip install json2xml

With Native Rust Acceleration (up to 129x faster)

For maximum performance, install the optional Rust extension:

# Install json2xml with Rust accelerationpip install json2xml[fast]
# Or install the Rust extension separatelypip install json2xml-rs

The Rust extension provides 57-129x faster conversion compared to pure Python in the latest benchmark. It's automatically used when available, with seamless fallback to pure Python.

As a CLI Tool

The library includes a command-line tool json2xml-py that gets installed automatically:

pip install json2xml
# Now you can use it from the command linejson2xml-py data.jsonjson2xml-py -s '{"name": "John", "age": 30}'json2xml-py -u https://api.example.com/data.json

For CLI options, run json2xml-py --help.

Features

json2xml supports the following features:

  • Conversion from a json string to XML
  • Conversion from a json file to XML
  • Conversion from an API that emits json data to XML
  • Compliant with the json-to-xml function specification from XPath 3.1
  • Command-line tool for easy conversion from the terminal

Usage

You can use the json2xml library in the following ways:

fromjson2xmlimportjson2xmlfromjson2xml.utilsimportreadfromurl, readfromstring, readfromjson# Convert JSON data from a URL to XMLdata=readfromurl("https://api.publicapis.org/entries")
print(json2xml.Json2xml(data).to_xml())
# Convert a JSON string to XMLdata=readfromstring(
'{"login":"mojombo","id":1,"avatar_url":"https://avatars0.githubusercontent.com/u/1?v=4"}'
)
print(json2xml.Json2xml(data).to_xml())
# Convert a JSON file to XMLdata=readfromjson("examples/licht.json")
print(json2xml.Json2xml(data).to_xml())

URL reads accept only credential-free HTTP(S), reject redirects and non-public destinations by default, pin public connections to their validated DNS address, and stop after 10 MiB of encoded or decoded content. Gzip and deflate responses honor Content-Length and are decoded incrementally; other content encodings are rejected. Trusted library callers can opt into a private endpoint with the boolean True or choose a smaller limit:

data=readfromurl(
"http://127.0.0.1:8000/data.json",
allow_private_networks=True,
max_response_bytes=1024*1024,
)

Custom Wrappers and Indentation

By default, a wrapper all and pretty True is set. However, you can easily change this in your code like this:

fromjson2xmlimportjson2xmlfromjson2xml.utilsimportreadfromurl, readfromstring, readfromjsondata=readfromstring(
'{"login":"mojombo","id":1,"avatar_url":"https://avatars0.githubusercontent.com/u/1?v=4"}'
)
print(json2xml.Json2xml(data, wrapper="all", pretty=True).to_xml())

Outputs this:

<?xml version="1.0" encoding="UTF-8"?>
<all>
<logintype="str">mojombo</login>
<idtype="int">1</id>
<avatar_urltype="str">https://avatars0.githubusercontent.com/u/1?v=4</avatar_url>
</all>

Omit List item

Assume the following json input

{
"my_items": [
{ "my_item": { "id": 1 } },
{ "my_item": { "id": 2 } }
],
"my_str_items": ["a", "b"]
}

By default, items in an array are wrapped in <item></item>.

Default output:

<?xml version="1.0" ?>
<all>
<my_itemstype="list">
<itemtype="dict">
<my_itemtype="dict">
<idtype="int">1</id>
</my_item>
</item>
<itemtype="dict">
<my_itemtype="dict">
<idtype="int">2</id>
</my_item>
</item>
</my_items>
<my_str_itemstype="list">
<itemtype="str">a</item>
<itemtype="str">b</item>
</my_str_items>
<emptytype="list"/>
</all>

However, you can change this behavior using the item_wrap property like this:

fromjson2xmlimportjson2xmlfromjson2xml.utilsimportreadfromurl, readfromstring, readfromjsondata=readfromstring('{"my_items":[{"my_item":{"id":1} },{"my_item":{"id":2} }],"my_str_items":["a","b"]}')
print(json2xml.Json2xml(data, item_wrap=False).to_xml())

Outputs this:

<?xml version="1.0" ?>
<all>
<my_itemstype="list">
<my_itemtype="dict">
<idtype="int">1</id>
</my_item>
<my_itemtype="dict">
<idtype="int">2</id>
</my_item>
</my_items>
<my_str_itemstype="str">a</my_str_items>
<my_str_itemstype="str">b</my_str_items>
</all>

Optional Attribute Type Support

You can also specify if the output XML needs to have type specified or not. Here is the usage:

fromjson2xmlimportjson2xmlfromjson2xml.utilsimportreadfromurl, readfromstring, readfromjsondata=readfromstring(
'{"login":"mojombo","id":1,"avatar_url":"https://avatars0.githubusercontent.com/u/1?v=4"}'
)
print(json2xml.Json2xml(data, wrapper="all", pretty=True, attr_type=False).to_xml())

Outputs this:

<?xml version="1.0" ?>
<all>
<login>mojombo</login>
<id>1</id>
<avatar_url>https://avatars0.githubusercontent.com/u/1?v=4</avatar_url>
</all>

XPath 3.1 Compliance Options

The library supports the optional xpath_format parameter which makes the output compliant with the json-to-xml function specification from XPath 3.1. When enabled, the XML output follows the standardized format defined by the W3C specification.

fromjson2xmlimportjson2xmlfromjson2xml.utilsimportreadfromstringdata=readfromstring(
'{"login":"mojombo","id":1,"avatar_url":"https://avatars0.githubusercontent.com/u/1?v=4"}'
)
# Use xpath_format=True for XPath 3.1 compliant outputprint(json2xml.Json2xml(data, xpath_format=True).to_xml())

The methods are simple and easy to use and there are also checks inside of code to exit cleanly in case any of the input(file, string or API URL) returns invalid JSON.

Development

This project uses modern Python development practices. Here's how to set up a development environment:

# Create and activate virtual environment (using uv - recommended)uv venvsource .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install dependenciesuv pip install -r requirements-dev.txtuv pip install -e .

Running Tests and Checks

We provide several ways to run tests and quality checks:

Using Make (recommended):

make test # Run tests with coveragemake lint # Run linting with ruffmake typecheck # Run type checking with mypymake check-all # Run all checks (lint, typecheck, test)

Using the development script:

python dev.py # Run all checkspython dev.py test # Run tests onlypython dev.py lint # Run linting onlypython dev.py typecheck # Run type checking only

Using tools directly:

pytest --cov=json2xml --cov-report=term -xvs tests -n autoruff check json2xml testsmypy json2xml tests

Rust Extension Development

The optional Rust extension (json2xml-rs) provides up to 129x faster performance in the latest benchmark. To develop or build the Rust extension:

Prerequisites:

# Install Rust (if not already installed)curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install maturin (Rust-Python build tool)uv pip install maturin

Building the extension:

# Development build (installs in current environment)cd rustuv pip install -e .
# Or using maturin directlymaturin develop --release
# Production wheel buildmaturin build --release

Running Rust benchmarks:

# After building the extensionpython benchmark_rust.py

The Rust code is in rust/src/lib.rs and uses PyO3 for Python bindings.

CLI Usage

The json2xml-py command-line tool provides an easy way to convert JSON to XML from the terminal.

Basic Examples

# Convert a JSON file to XMLjson2xml-py data.json
# Convert with custom wrapper elementjson2xml-py -w root data.json
# Read JSON from stringjson2xml-py -s '{"name": "John", "age": 30}'
# Read from stdincat data.json | json2xml-py -
# Output to filejson2xml-py -o output.xml data.json
# Use XPath 3.1 formatjson2xml-py -x data.json
# Disable pretty printing and type attributesjson2xml-py --no-pretty --no-type data.json

CLI Options

Input Options:
-u, --url string Read JSON from URL
-s, --string string Read JSON from string
[input-file] Read JSON from file (use - for stdin)
Output Options:
-o, --output string Output file (default: stdout)
Conversion Options:
-w, --wrapper string Wrapper element name (default "all")
-r, --root Include root element (default true)
-p, --pretty Pretty print output (default true)
-t, --type Include type attributes (default true)
-i, --item-wrap Wrap list items in <item> elements (default true)
-x, --xpath Use XPath 3.1 json-to-xml format
-c, --cdata Wrap string values in CDATA sections
-l, --list-headers Repeat headers for each list item
Other Options:
-v, --version Show version information
-h, --help Show help message

Go Version

A Go port of this library is available at json2xml-go.

Install the Go CLI:

go install github.com/vinitkumar/json2xml-go/cmd/json2xml@latest

The Go version provides the same features and a native compiled binary for maximum performance.

Rust Extension (PyO3)

For users who need maximum performance within Python, json2xml includes an optional native Rust extension built with PyO3:

pip install json2xml[fast]

Rust vs Pure Python Performance:

Test CasePure PythonRust ExtensionSpeedup
Small JSON (47 bytes)31.49µs0.55µs56.8x
Medium JSON (3.2 KB)1.69ms16.15µs105.0x
Large JSON (32 KB)17.97ms168.21µs106.8x
Very Large JSON (323 KB)183.33ms1.42ms129.0x

Usage with Rust Extension:

# Automatic backend selection (recommended)fromjson2xml.dicttoxml_fastimportdicttoxml, get_backendprint(f"Using backend: {get_backend()}") # 'rust' or 'python'data= {"name": "John", "age": 30}
xml_bytes=dicttoxml(data)

The dicttoxml_fast module automatically uses the Rust backend when available and falls back to pure Python for unsupported features (like xpath_format, xml_namespaces, or custom item_func).

Platform Support:

Pre-built wheels are available for:

  • Linux (x86_64, aarch64)
  • macOS (x86_64, arm64/Apple Silicon)
  • Windows (x86_64)

For other platforms, the pure Python version is used automatically.

Performance Benchmarks

Comprehensive benchmarks comparing all implementations (Apple Silicon, macOS 26.4.1, Python 3.14.4, April 2026):

Test CasePythonRustGoZigBest
Small (47B)31.49µs0.55µs4.09ms2.02msRust (56.8x)
Medium (3.2KB)1.69ms16.15µs4.07ms2.09msRust (105.0x)
Large (32KB)17.97ms168.21µs4.10ms2.42msRust (106.8x)
Very Large (323KB)183.33ms1.42ms4.20ms5.12msRust (129.0x)

Key Findings:

  • Rust extension: 57-129x faster than Python, zero process overhead (best for Python users)
  • Go CLI: 43.6x faster for very large files (300KB+), but has ~4ms startup overhead
  • Zig CLI: 7.4x faster for large files and 35.8x faster for very large files, with ~2ms startup overhead

Recommendation by Use Case:

  • Python library calls: Use pip install json2xml[fast] (Rust, up to 129x faster)
  • Large file CLI processing: Use json2xml-go or json2xml-zig depending on your workload
  • Pure Python required: Use pip install json2xml

For detailed benchmarks, see BENCHMARKS.md.

Other Implementations

This library is also available in other languages:

  • Rust: json2xml-rs - up to 129x faster, Python extension via PyO3
  • Go: json2xml-go - 43.6x faster for very large files, native CLI
  • Zig: json2xml-zig - 35.8x faster for very large files, native CLI

Help and Support to maintain this project

About

JSON-to-XML converter for Python, accelerated with a native Rust extension.

Topics

Resources

Contributing

Security policy

Stars

109 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages