json2xml 6.0.7__tar.gz → 6.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {json2xml-6.0.7 → json2xml-6.2.0}/CONTRIBUTING.rst +12 -1
- {json2xml-6.0.7 → json2xml-6.2.0}/HISTORY.rst +18 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/PKG-INFO +136 -5
- {json2xml-6.0.7 → json2xml-6.2.0}/README.rst +132 -2
- json2xml-6.2.0/docs/benchmarks.rst +203 -0
- json2xml-6.2.0/docs/rust_memory_benchmark.rst +110 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/usage.rst +46 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml/__init__.py +1 -1
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml/cli.py +25 -5
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml/dicttoxml.py +150 -40
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml/dicttoxml_fast.py +10 -9
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml/json2xml.py +6 -4
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml/utils.py +19 -5
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml.egg-info/PKG-INFO +136 -5
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml.egg-info/SOURCES.txt +3 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml.egg-info/requires.txt +3 -2
- {json2xml-6.0.7 → json2xml-6.2.0}/pyproject.toml +4 -3
- {json2xml-6.0.7 → json2xml-6.2.0}/requirements.in +1 -1
- {json2xml-6.0.7 → json2xml-6.2.0}/setup.cfg +1 -1
- {json2xml-6.0.7 → json2xml-6.2.0}/tests/test_cli.py +35 -5
- {json2xml-6.0.7 → json2xml-6.2.0}/tests/test_dict2xml.py +78 -0
- json2xml-6.2.0/tests/test_dicttoxml_fast_fallback.py +137 -0
- json2xml-6.2.0/tests/test_dicttoxml_unit.py +163 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/tests/test_json2xml.py +27 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/tests/test_rust_dicttoxml.py +4 -4
- {json2xml-6.0.7 → json2xml-6.2.0}/tests/test_utils.py +2 -2
- json2xml-6.0.7/docs/benchmarks.rst +0 -221
- {json2xml-6.0.7 → json2xml-6.2.0}/AUTHORS.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/LICENSE +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/MANIFEST.in +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/Makefile +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/authors.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/conf.py +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/contributing.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/history.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/index.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/installation.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/json2xml.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/make.bat +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/modules.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/docs/readme.rst +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml/types.py +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml.egg-info/dependency_links.txt +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml.egg-info/entry_points.txt +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/json2xml.egg-info/top_level.txt +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/setup.py +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/tests/__init__.py +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/tests/conftest.py +0 -0
- {json2xml-6.0.7 → json2xml-6.2.0}/tests/test_missing_coverage.py +0 -0
|
@@ -9,6 +9,17 @@ helps, and credit will always be given.
|
|
|
9
9
|
|
|
10
10
|
You can contribute in many ways:
|
|
11
11
|
|
|
12
|
+
Good First Contributions
|
|
13
|
+
------------------------
|
|
14
|
+
|
|
15
|
+
If you are new to the project, these are useful places to start:
|
|
16
|
+
|
|
17
|
+
* Improve examples for real-world API responses, files, and command-line usage.
|
|
18
|
+
* Add small tests around conversion options such as wrappers, list handling, CDATA, and XPath output.
|
|
19
|
+
* Improve benchmark documentation or add a reproducible benchmark case.
|
|
20
|
+
* Polish CLI behavior, error messages, and help text.
|
|
21
|
+
* Review the roadmap in ``ROADMAP.md`` and open a focused issue before starting larger changes.
|
|
22
|
+
|
|
12
23
|
Types of Contributions
|
|
13
24
|
----------------------
|
|
14
25
|
|
|
@@ -99,7 +110,7 @@ Ready to contribute? Here's how to set up `json2xml` for local development.
|
|
|
99
110
|
Rust Extension Development
|
|
100
111
|
--------------------------
|
|
101
112
|
|
|
102
|
-
The ``json2xml-rs`` Rust extension provides ~
|
|
113
|
+
The ``json2xml-rs`` Rust extension provides ~57-129x faster performance in the current benchmark. If you want to contribute to the Rust extension:
|
|
103
114
|
|
|
104
115
|
**Prerequisites**
|
|
105
116
|
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
|
|
2
|
+
6.2.0 / 2026-06-05
|
|
3
|
+
==================
|
|
4
|
+
|
|
5
|
+
* feat: reduce peak serializer memory in the pure Python rooted-output path
|
|
6
|
+
* feat: reduce Rust extension peak serializer memory by writing directly into Python bytes
|
|
7
|
+
* fix: split PyO3 extension-module linking so ``cargo test`` works on macOS
|
|
8
|
+
* chore: release ``json2xml-rs`` 0.3.0 and make ``json2xml[fast]`` require the memory-saving Rust package
|
|
9
|
+
* chore: update the Rust extension crate to Rust 2024 with rust-version 1.96
|
|
10
|
+
* docs: add reproducible Rust memory benchmark results showing about 49% lower serializer RSS delta
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
6.1.0 / 2026-05-04
|
|
14
|
+
==================
|
|
15
|
+
|
|
16
|
+
* fix: address open contribution issues (#292)
|
|
17
|
+
* docs: improve README and add public roadmap (#287)
|
|
18
|
+
|
|
19
|
+
|
|
2
20
|
6.0.7 / 2026-04-26
|
|
3
21
|
==================
|
|
4
22
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: json2xml
|
|
3
|
-
Version: 6.0
|
|
3
|
+
Version: 6.2.0
|
|
4
4
|
Summary: Simple Python Library to convert JSON to XML
|
|
5
5
|
Author-email: Vinit Kumar <mail@vinitkumar.me>
|
|
6
6
|
License: Apache Software License 2.0
|
|
@@ -23,15 +23,16 @@ Description-Content-Type: text/x-rst
|
|
|
23
23
|
License-File: LICENSE
|
|
24
24
|
License-File: AUTHORS.rst
|
|
25
25
|
Requires-Dist: defusedxml
|
|
26
|
-
Requires-Dist: urllib3
|
|
26
|
+
Requires-Dist: urllib3>=2.7.0
|
|
27
27
|
Provides-Extra: dev
|
|
28
28
|
Requires-Dist: pytest>=8.4.1; extra == "dev"
|
|
29
29
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
30
30
|
Requires-Dist: coverage; extra == "dev"
|
|
31
31
|
Requires-Dist: setuptools; extra == "dev"
|
|
32
|
+
Requires-Dist: pygments>=2.20.0; extra == "dev"
|
|
32
33
|
Requires-Dist: xmltodict>=0.12.0; extra == "dev"
|
|
33
34
|
Provides-Extra: fast
|
|
34
|
-
Requires-Dist: json2xml-rs>=0.
|
|
35
|
+
Requires-Dist: json2xml-rs>=0.3.0; extra == "fast"
|
|
35
36
|
Dynamic: license-file
|
|
36
37
|
|
|
37
38
|
.. image:: ./json2xml-hero.png
|
|
@@ -54,7 +55,7 @@ json2xml
|
|
|
54
55
|
.. image:: https://codecov.io/gh/vinitkumar/json2xml/branch/master/graph/badge.svg?token=Yt2h55eTL2
|
|
55
56
|
:target: https://codecov.io/gh/vinitkumar/json2xml
|
|
56
57
|
|
|
57
|
-
json2xml is a Python library
|
|
58
|
+
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.
|
|
58
59
|
|
|
59
60
|
Documentation: https://json2xml.readthedocs.io.
|
|
60
61
|
|
|
@@ -62,6 +63,137 @@ The library was initially dependent on the `dict2xml` project, but it has now be
|
|
|
62
63
|
|
|
63
64
|
**Looking for a Go version?** Check out `json2xml-go <https://github.com/vinitkumar/json2xml-go>`_, a Go port of this library with identical features and a native CLI tool.
|
|
64
65
|
|
|
66
|
+
Why json2xml?
|
|
67
|
+
^^^^^^^^^^^^^
|
|
68
|
+
|
|
69
|
+
Use json2xml when you need:
|
|
70
|
+
|
|
71
|
+
* A Python library for turning dictionaries, strings, files, or API responses into XML
|
|
72
|
+
* A command-line tool for quick JSON-to-XML conversion from scripts and terminals
|
|
73
|
+
* Optional Rust acceleration with automatic fallback to the pure Python implementation
|
|
74
|
+
* XPath 3.1 compatible output when standards-friendly XML is required
|
|
75
|
+
* A small, focused project with tests, docs, benchmarks, and multiple native implementation experiments
|
|
76
|
+
|
|
77
|
+
Quick Start
|
|
78
|
+
^^^^^^^^^^^
|
|
79
|
+
|
|
80
|
+
Install the Python package:
|
|
81
|
+
|
|
82
|
+
.. code-block:: console
|
|
83
|
+
|
|
84
|
+
pip install json2xml
|
|
85
|
+
|
|
86
|
+
Use it from Python:
|
|
87
|
+
|
|
88
|
+
.. code-block:: python
|
|
89
|
+
|
|
90
|
+
from json2xml import json2xml
|
|
91
|
+
from json2xml.utils import readfromstring
|
|
92
|
+
|
|
93
|
+
data = readfromstring('{"name": "Ada", "language": "Python"}')
|
|
94
|
+
print(json2xml.Json2xml(data).to_xml())
|
|
95
|
+
|
|
96
|
+
Use it from the terminal:
|
|
97
|
+
|
|
98
|
+
.. code-block:: console
|
|
99
|
+
|
|
100
|
+
json2xml-py -s '{"name": "Ada", "language": "Python"}'
|
|
101
|
+
|
|
102
|
+
Install the accelerated path:
|
|
103
|
+
|
|
104
|
+
.. code-block:: console
|
|
105
|
+
|
|
106
|
+
pip install json2xml[fast]
|
|
107
|
+
|
|
108
|
+
Real-world Examples
|
|
109
|
+
^^^^^^^^^^^^^^^^^^^
|
|
110
|
+
|
|
111
|
+
Convert a JSON API response in Python when another system expects XML:
|
|
112
|
+
|
|
113
|
+
.. code-block:: python
|
|
114
|
+
|
|
115
|
+
from json2xml import json2xml
|
|
116
|
+
|
|
117
|
+
api_response = {"user": {"id": 7, "name": "Ada"}, "active": True}
|
|
118
|
+
print(json2xml.Json2xml(api_response, pretty=False).to_xml().decode("utf-8"))
|
|
119
|
+
|
|
120
|
+
Output:
|
|
121
|
+
|
|
122
|
+
.. code-block:: xml
|
|
123
|
+
|
|
124
|
+
<?xml version="1.0" encoding="UTF-8" ?><all><user type="dict"><id type="int">7</id><name type="str">Ada</name></user><active type="bool">true</active></all>
|
|
125
|
+
|
|
126
|
+
Convert a local JSON export from the shell:
|
|
127
|
+
|
|
128
|
+
.. code-block:: console
|
|
129
|
+
|
|
130
|
+
cat > orders.json <<'JSON'
|
|
131
|
+
{"orders":[{"id":"A100","total":19.99},{"id":"A101","total":5.5}]}
|
|
132
|
+
JSON
|
|
133
|
+
json2xml-py --no-pretty --no-type orders.json
|
|
134
|
+
|
|
135
|
+
Output:
|
|
136
|
+
|
|
137
|
+
.. code-block:: xml
|
|
138
|
+
|
|
139
|
+
<?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>
|
|
140
|
+
|
|
141
|
+
Convert stdin in a shell pipeline:
|
|
142
|
+
|
|
143
|
+
.. code-block:: console
|
|
144
|
+
|
|
145
|
+
printf '%s\n' '{"event":"deploy","status":"ok"}' | json2xml-py --no-pretty --no-type -
|
|
146
|
+
|
|
147
|
+
Output:
|
|
148
|
+
|
|
149
|
+
.. code-block:: xml
|
|
150
|
+
|
|
151
|
+
<?xml version="1.0" encoding="UTF-8" ?><all><event>deploy</event><status>ok</status></all>
|
|
152
|
+
|
|
153
|
+
Performance Snapshot
|
|
154
|
+
^^^^^^^^^^^^^^^^^^^^
|
|
155
|
+
|
|
156
|
+
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.
|
|
157
|
+
|
|
158
|
+
.. list-table::
|
|
159
|
+
:header-rows: 1
|
|
160
|
+
:widths: 30 20 20 15
|
|
161
|
+
|
|
162
|
+
* - Test Case
|
|
163
|
+
- Pure Python
|
|
164
|
+
- Rust Extension
|
|
165
|
+
- Speedup
|
|
166
|
+
* - **Small JSON** (47 bytes)
|
|
167
|
+
- 31.49µs
|
|
168
|
+
- 0.55µs
|
|
169
|
+
- **56.8x**
|
|
170
|
+
* - **Medium JSON** (3.2 KB)
|
|
171
|
+
- 1.69ms
|
|
172
|
+
- 16.15µs
|
|
173
|
+
- **105.0x**
|
|
174
|
+
* - **Large JSON** (32 KB)
|
|
175
|
+
- 17.97ms
|
|
176
|
+
- 168.21µs
|
|
177
|
+
- **106.8x**
|
|
178
|
+
* - **Very Large JSON** (323 KB)
|
|
179
|
+
- 183.33ms
|
|
180
|
+
- 1.42ms
|
|
181
|
+
- **129.0x**
|
|
182
|
+
|
|
183
|
+
See `BENCHMARKS.md <https://github.com/vinitkumar/json2xml/blob/master/BENCHMARKS.md>`_ for the full Python, Rust, Go, and Zig comparison.
|
|
184
|
+
|
|
185
|
+
Project Roadmap
|
|
186
|
+
^^^^^^^^^^^^^^^
|
|
187
|
+
|
|
188
|
+
The next phase of json2xml is focused on making the project easier to adopt, benchmark, and contribute to:
|
|
189
|
+
|
|
190
|
+
* Improve examples for common API, file, and CLI workflows
|
|
191
|
+
* Add clearer contribution paths for docs, CLI polish, and benchmark coverage
|
|
192
|
+
* Keep comparing Python, Rust, Go, and Zig implementations with reproducible benchmarks
|
|
193
|
+
* Continue hardening the Rust extension fallback behavior across platforms
|
|
194
|
+
|
|
195
|
+
See `ROADMAP.md <https://github.com/vinitkumar/json2xml/blob/master/ROADMAP.md>`_ for more detail.
|
|
196
|
+
|
|
65
197
|
|
|
66
198
|
|
|
67
199
|
Architecture Diagram
|
|
@@ -574,4 +706,3 @@ Help and Support to maintain this project
|
|
|
574
706
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
575
707
|
|
|
576
708
|
- You can sponsor my work for this plugin here: https://github.com/sponsors/vinitkumar/
|
|
577
|
-
|
|
@@ -18,7 +18,7 @@ json2xml
|
|
|
18
18
|
.. image:: https://codecov.io/gh/vinitkumar/json2xml/branch/master/graph/badge.svg?token=Yt2h55eTL2
|
|
19
19
|
:target: https://codecov.io/gh/vinitkumar/json2xml
|
|
20
20
|
|
|
21
|
-
json2xml is a Python library
|
|
21
|
+
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.
|
|
22
22
|
|
|
23
23
|
Documentation: https://json2xml.readthedocs.io.
|
|
24
24
|
|
|
@@ -26,6 +26,137 @@ The library was initially dependent on the `dict2xml` project, but it has now be
|
|
|
26
26
|
|
|
27
27
|
**Looking for a Go version?** Check out `json2xml-go <https://github.com/vinitkumar/json2xml-go>`_, a Go port of this library with identical features and a native CLI tool.
|
|
28
28
|
|
|
29
|
+
Why json2xml?
|
|
30
|
+
^^^^^^^^^^^^^
|
|
31
|
+
|
|
32
|
+
Use json2xml when you need:
|
|
33
|
+
|
|
34
|
+
* A Python library for turning dictionaries, strings, files, or API responses into XML
|
|
35
|
+
* A command-line tool for quick JSON-to-XML conversion from scripts and terminals
|
|
36
|
+
* Optional Rust acceleration with automatic fallback to the pure Python implementation
|
|
37
|
+
* XPath 3.1 compatible output when standards-friendly XML is required
|
|
38
|
+
* A small, focused project with tests, docs, benchmarks, and multiple native implementation experiments
|
|
39
|
+
|
|
40
|
+
Quick Start
|
|
41
|
+
^^^^^^^^^^^
|
|
42
|
+
|
|
43
|
+
Install the Python package:
|
|
44
|
+
|
|
45
|
+
.. code-block:: console
|
|
46
|
+
|
|
47
|
+
pip install json2xml
|
|
48
|
+
|
|
49
|
+
Use it from Python:
|
|
50
|
+
|
|
51
|
+
.. code-block:: python
|
|
52
|
+
|
|
53
|
+
from json2xml import json2xml
|
|
54
|
+
from json2xml.utils import readfromstring
|
|
55
|
+
|
|
56
|
+
data = readfromstring('{"name": "Ada", "language": "Python"}')
|
|
57
|
+
print(json2xml.Json2xml(data).to_xml())
|
|
58
|
+
|
|
59
|
+
Use it from the terminal:
|
|
60
|
+
|
|
61
|
+
.. code-block:: console
|
|
62
|
+
|
|
63
|
+
json2xml-py -s '{"name": "Ada", "language": "Python"}'
|
|
64
|
+
|
|
65
|
+
Install the accelerated path:
|
|
66
|
+
|
|
67
|
+
.. code-block:: console
|
|
68
|
+
|
|
69
|
+
pip install json2xml[fast]
|
|
70
|
+
|
|
71
|
+
Real-world Examples
|
|
72
|
+
^^^^^^^^^^^^^^^^^^^
|
|
73
|
+
|
|
74
|
+
Convert a JSON API response in Python when another system expects XML:
|
|
75
|
+
|
|
76
|
+
.. code-block:: python
|
|
77
|
+
|
|
78
|
+
from json2xml import json2xml
|
|
79
|
+
|
|
80
|
+
api_response = {"user": {"id": 7, "name": "Ada"}, "active": True}
|
|
81
|
+
print(json2xml.Json2xml(api_response, pretty=False).to_xml().decode("utf-8"))
|
|
82
|
+
|
|
83
|
+
Output:
|
|
84
|
+
|
|
85
|
+
.. code-block:: xml
|
|
86
|
+
|
|
87
|
+
<?xml version="1.0" encoding="UTF-8" ?><all><user type="dict"><id type="int">7</id><name type="str">Ada</name></user><active type="bool">true</active></all>
|
|
88
|
+
|
|
89
|
+
Convert a local JSON export from the shell:
|
|
90
|
+
|
|
91
|
+
.. code-block:: console
|
|
92
|
+
|
|
93
|
+
cat > orders.json <<'JSON'
|
|
94
|
+
{"orders":[{"id":"A100","total":19.99},{"id":"A101","total":5.5}]}
|
|
95
|
+
JSON
|
|
96
|
+
json2xml-py --no-pretty --no-type orders.json
|
|
97
|
+
|
|
98
|
+
Output:
|
|
99
|
+
|
|
100
|
+
.. code-block:: xml
|
|
101
|
+
|
|
102
|
+
<?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>
|
|
103
|
+
|
|
104
|
+
Convert stdin in a shell pipeline:
|
|
105
|
+
|
|
106
|
+
.. code-block:: console
|
|
107
|
+
|
|
108
|
+
printf '%s\n' '{"event":"deploy","status":"ok"}' | json2xml-py --no-pretty --no-type -
|
|
109
|
+
|
|
110
|
+
Output:
|
|
111
|
+
|
|
112
|
+
.. code-block:: xml
|
|
113
|
+
|
|
114
|
+
<?xml version="1.0" encoding="UTF-8" ?><all><event>deploy</event><status>ok</status></all>
|
|
115
|
+
|
|
116
|
+
Performance Snapshot
|
|
117
|
+
^^^^^^^^^^^^^^^^^^^^
|
|
118
|
+
|
|
119
|
+
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.
|
|
120
|
+
|
|
121
|
+
.. list-table::
|
|
122
|
+
:header-rows: 1
|
|
123
|
+
:widths: 30 20 20 15
|
|
124
|
+
|
|
125
|
+
* - Test Case
|
|
126
|
+
- Pure Python
|
|
127
|
+
- Rust Extension
|
|
128
|
+
- Speedup
|
|
129
|
+
* - **Small JSON** (47 bytes)
|
|
130
|
+
- 31.49µs
|
|
131
|
+
- 0.55µs
|
|
132
|
+
- **56.8x**
|
|
133
|
+
* - **Medium JSON** (3.2 KB)
|
|
134
|
+
- 1.69ms
|
|
135
|
+
- 16.15µs
|
|
136
|
+
- **105.0x**
|
|
137
|
+
* - **Large JSON** (32 KB)
|
|
138
|
+
- 17.97ms
|
|
139
|
+
- 168.21µs
|
|
140
|
+
- **106.8x**
|
|
141
|
+
* - **Very Large JSON** (323 KB)
|
|
142
|
+
- 183.33ms
|
|
143
|
+
- 1.42ms
|
|
144
|
+
- **129.0x**
|
|
145
|
+
|
|
146
|
+
See `BENCHMARKS.md <https://github.com/vinitkumar/json2xml/blob/master/BENCHMARKS.md>`_ for the full Python, Rust, Go, and Zig comparison.
|
|
147
|
+
|
|
148
|
+
Project Roadmap
|
|
149
|
+
^^^^^^^^^^^^^^^
|
|
150
|
+
|
|
151
|
+
The next phase of json2xml is focused on making the project easier to adopt, benchmark, and contribute to:
|
|
152
|
+
|
|
153
|
+
* Improve examples for common API, file, and CLI workflows
|
|
154
|
+
* Add clearer contribution paths for docs, CLI polish, and benchmark coverage
|
|
155
|
+
* Keep comparing Python, Rust, Go, and Zig implementations with reproducible benchmarks
|
|
156
|
+
* Continue hardening the Rust extension fallback behavior across platforms
|
|
157
|
+
|
|
158
|
+
See `ROADMAP.md <https://github.com/vinitkumar/json2xml/blob/master/ROADMAP.md>`_ for more detail.
|
|
159
|
+
|
|
29
160
|
|
|
30
161
|
|
|
31
162
|
Architecture Diagram
|
|
@@ -538,4 +669,3 @@ Help and Support to maintain this project
|
|
|
538
669
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
539
670
|
|
|
540
671
|
- You can sponsor my work for this plugin here: https://github.com/sponsors/vinitkumar/
|
|
541
|
-
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Benchmarks
|
|
2
|
+
==========
|
|
3
|
+
|
|
4
|
+
Comprehensive performance comparison between all json2xml implementations.
|
|
5
|
+
|
|
6
|
+
Test Environment
|
|
7
|
+
----------------
|
|
8
|
+
|
|
9
|
+
* **Machine**: Apple Silicon (arm64)
|
|
10
|
+
* **OS**: macOS 26.5 (Darwin 25.5.0)
|
|
11
|
+
* **Python**: 3.14.4
|
|
12
|
+
* **Date**: May 27, 2026
|
|
13
|
+
* **CLI tools**: ``json2xml-go`` and ``json2xml-zig`` from ``/Users/vinitkumar/.local/bin``
|
|
14
|
+
|
|
15
|
+
Implementations Tested
|
|
16
|
+
~~~~~~~~~~~~~~~~~~~~~~
|
|
17
|
+
|
|
18
|
+
.. list-table::
|
|
19
|
+
:header-rows: 1
|
|
20
|
+
:widths: 25 20 55
|
|
21
|
+
|
|
22
|
+
* - Implementation
|
|
23
|
+
- Type
|
|
24
|
+
- Notes
|
|
25
|
+
* - Python
|
|
26
|
+
- Library
|
|
27
|
+
- Pure Python ``json2xml``
|
|
28
|
+
* - Rust
|
|
29
|
+
- Library
|
|
30
|
+
- Native extension via PyO3, imported as ``json2xml_rs``
|
|
31
|
+
* - Go
|
|
32
|
+
- CLI
|
|
33
|
+
- Standalone ``json2xml-go`` binary
|
|
34
|
+
* - Zig
|
|
35
|
+
- CLI
|
|
36
|
+
- Standalone ``json2xml-zig`` binary
|
|
37
|
+
|
|
38
|
+
Test Data
|
|
39
|
+
~~~~~~~~~
|
|
40
|
+
|
|
41
|
+
.. list-table::
|
|
42
|
+
:header-rows: 1
|
|
43
|
+
:widths: 20 55 25
|
|
44
|
+
|
|
45
|
+
* - Size
|
|
46
|
+
- Description
|
|
47
|
+
- Bytes
|
|
48
|
+
* - Small
|
|
49
|
+
- Simple object ``{"name": "John", "age": 30, "city": "New York"}``
|
|
50
|
+
- 47
|
|
51
|
+
* - Medium
|
|
52
|
+
- 10 generated records with nested structures
|
|
53
|
+
- 3,215
|
|
54
|
+
* - bigexample.json
|
|
55
|
+
- Real-world patent data
|
|
56
|
+
- 2,018
|
|
57
|
+
* - Large
|
|
58
|
+
- 100 generated records with nested structures
|
|
59
|
+
- 32,206
|
|
60
|
+
* - Very Large
|
|
61
|
+
- 1,000 generated records with nested structures
|
|
62
|
+
- 323,131
|
|
63
|
+
|
|
64
|
+
Results
|
|
65
|
+
-------
|
|
66
|
+
|
|
67
|
+
Performance Summary
|
|
68
|
+
~~~~~~~~~~~~~~~~~~~
|
|
69
|
+
|
|
70
|
+
.. list-table::
|
|
71
|
+
:header-rows: 1
|
|
72
|
+
:widths: 28 18 18 18 18
|
|
73
|
+
|
|
74
|
+
* - Test Case
|
|
75
|
+
- Python
|
|
76
|
+
- Rust
|
|
77
|
+
- Go
|
|
78
|
+
- Zig
|
|
79
|
+
* - Small (47B)
|
|
80
|
+
- 3.19µs
|
|
81
|
+
- 0.86µs
|
|
82
|
+
- 6.05ms
|
|
83
|
+
- 3.08ms
|
|
84
|
+
* - Medium (3.2KB)
|
|
85
|
+
- 214.83µs
|
|
86
|
+
- 18.41µs
|
|
87
|
+
- 5.85ms
|
|
88
|
+
- 3.12ms
|
|
89
|
+
* - bigexample (2KB)
|
|
90
|
+
- 91.20µs
|
|
91
|
+
- 7.32µs
|
|
92
|
+
- 5.76ms
|
|
93
|
+
- 3.08ms
|
|
94
|
+
* - Large (32KB)
|
|
95
|
+
- 2.07ms
|
|
96
|
+
- 175.46µs
|
|
97
|
+
- 5.89ms
|
|
98
|
+
- 3.73ms
|
|
99
|
+
* - Very Large (323KB)
|
|
100
|
+
- 21.20ms
|
|
101
|
+
- 1.48ms
|
|
102
|
+
- 6.82ms
|
|
103
|
+
- 7.82ms
|
|
104
|
+
|
|
105
|
+
Speedup vs Pure Python
|
|
106
|
+
~~~~~~~~~~~~~~~~~~~~~~
|
|
107
|
+
|
|
108
|
+
.. list-table::
|
|
109
|
+
:header-rows: 1
|
|
110
|
+
:widths: 34 22 22 22
|
|
111
|
+
|
|
112
|
+
* - Test Case
|
|
113
|
+
- Rust
|
|
114
|
+
- Go
|
|
115
|
+
- Zig
|
|
116
|
+
* - Small (47B)
|
|
117
|
+
- **3.7x**
|
|
118
|
+
- 0.0x*
|
|
119
|
+
- 0.0x*
|
|
120
|
+
* - Medium (3.2KB)
|
|
121
|
+
- **11.7x**
|
|
122
|
+
- 0.0x*
|
|
123
|
+
- 0.1x*
|
|
124
|
+
* - bigexample (2KB)
|
|
125
|
+
- **12.5x**
|
|
126
|
+
- 0.0x*
|
|
127
|
+
- 0.0x*
|
|
128
|
+
* - Large (32KB)
|
|
129
|
+
- **11.8x**
|
|
130
|
+
- 0.4x*
|
|
131
|
+
- 0.6x*
|
|
132
|
+
* - Very Large (323KB)
|
|
133
|
+
- **14.4x**
|
|
134
|
+
- **3.1x**
|
|
135
|
+
- **2.7x**
|
|
136
|
+
|
|
137
|
+
*CLI tools have process spawn overhead of about 3-6ms, which dominates for small inputs.*
|
|
138
|
+
|
|
139
|
+
Key Observations
|
|
140
|
+
----------------
|
|
141
|
+
|
|
142
|
+
Rust remains the best option for Python library calls. It avoids process overhead and is about 4-14x faster than the optimized pure Python path in this run.
|
|
143
|
+
|
|
144
|
+
Recent pure Python improvements substantially reduced conversion time. Medium and large inputs are roughly an order of magnitude faster than the April 2026 baseline, so relative Rust speedups are lower even though Rust is still fastest.
|
|
145
|
+
|
|
146
|
+
Go and Zig remain useful for native CLI workflows. They are slower for small and medium inputs because startup dominates, but both beat Python on the 323KB workload when full CLI process time is measured.
|
|
147
|
+
|
|
148
|
+
See ``docs/rust_memory_benchmark.rst`` for the June 2026 Rust peak-memory comparison between the previous extension-boundary copy and the Python bytes-writer implementation.
|
|
149
|
+
|
|
150
|
+
When to Use Each Implementation
|
|
151
|
+
-------------------------------
|
|
152
|
+
|
|
153
|
+
.. list-table::
|
|
154
|
+
:header-rows: 1
|
|
155
|
+
:widths: 40 25 35
|
|
156
|
+
|
|
157
|
+
* - Use Case
|
|
158
|
+
- Recommended
|
|
159
|
+
- Why
|
|
160
|
+
* - Python library calls
|
|
161
|
+
- **Rust**
|
|
162
|
+
- 4-14x faster, no process overhead
|
|
163
|
+
* - Small files via CLI
|
|
164
|
+
- **Zig**
|
|
165
|
+
- Fastest startup among native CLIs in this run
|
|
166
|
+
* - Large files via CLI
|
|
167
|
+
- **Go** or **Zig**
|
|
168
|
+
- Both are faster than Python at 323KB
|
|
169
|
+
* - Batch processing
|
|
170
|
+
- **Go** or **Rust**
|
|
171
|
+
- Choose based on shell vs Python integration
|
|
172
|
+
* - Pure Python required
|
|
173
|
+
- **Python**
|
|
174
|
+
- Always available
|
|
175
|
+
|
|
176
|
+
Running the Benchmarks
|
|
177
|
+
----------------------
|
|
178
|
+
|
|
179
|
+
Run benchmarks from a clean checkout with the project installed in an isolated environment.
|
|
180
|
+
|
|
181
|
+
.. code-block:: bash
|
|
182
|
+
|
|
183
|
+
uv venv
|
|
184
|
+
source .venv/bin/activate
|
|
185
|
+
uv pip install -e .
|
|
186
|
+
python benchmark_all.py
|
|
187
|
+
|
|
188
|
+
For Rust benchmarks, install the extension into the same environment.
|
|
189
|
+
|
|
190
|
+
.. code-block:: bash
|
|
191
|
+
|
|
192
|
+
uv pip install maturin
|
|
193
|
+
cd rust
|
|
194
|
+
maturin develop --release
|
|
195
|
+
cd ..
|
|
196
|
+
|
|
197
|
+
For native CLI benchmarks, install the external tools and verify that the commands are visible.
|
|
198
|
+
|
|
199
|
+
.. code-block:: bash
|
|
200
|
+
|
|
201
|
+
go install github.com/vinitkumar/json2xml-go@latest
|
|
202
|
+
which json2xml-go
|
|
203
|
+
which json2xml-zig
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Rust Memory Benchmark
|
|
2
|
+
=====================
|
|
3
|
+
|
|
4
|
+
This benchmark compares peak memory usage before and after the Rust serializer started writing directly into Python ``bytes``.
|
|
5
|
+
|
|
6
|
+
Summary
|
|
7
|
+
-------
|
|
8
|
+
|
|
9
|
+
The current branch reduces serializer peak RSS by about **77.44 MiB** on a 100,000-record payload that produces **78.17 MiB** of XML. That is a **49.1% reduction** in serializer memory delta compared with the previous PR commit.
|
|
10
|
+
|
|
11
|
+
.. list-table::
|
|
12
|
+
:header-rows: 1
|
|
13
|
+
:widths: 24 22 22 22 22
|
|
14
|
+
|
|
15
|
+
* - Version
|
|
16
|
+
- Commit
|
|
17
|
+
- Avg peak RSS
|
|
18
|
+
- Avg serializer delta
|
|
19
|
+
- Avg time
|
|
20
|
+
* - Previous
|
|
21
|
+
- ``7dd86b0``
|
|
22
|
+
- 349.15 MiB
|
|
23
|
+
- 157.70 MiB
|
|
24
|
+
- 0.180s
|
|
25
|
+
* - Current
|
|
26
|
+
- ``07d840f``
|
|
27
|
+
- 271.65 MiB
|
|
28
|
+
- 80.26 MiB
|
|
29
|
+
- 0.265s
|
|
30
|
+
|
|
31
|
+
The memory result matches the implementation change: the previous version held roughly one final XML payload in Rust plus one Python ``bytes`` payload, while the current version writes into the Python ``bytes`` object directly.
|
|
32
|
+
|
|
33
|
+
Methodology
|
|
34
|
+
-----------
|
|
35
|
+
|
|
36
|
+
The benchmark uses ``benchmark_memory_rust.py`` with a deterministic generated payload so the Rust fast path can be measured without file parsing or pure-Python fallback behavior.
|
|
37
|
+
|
|
38
|
+
* Machine: Apple Silicon arm64
|
|
39
|
+
* OS: macOS 26.5
|
|
40
|
+
* Python: 3.14.0
|
|
41
|
+
* Build: ``python3 -m maturin develop --release --offline``
|
|
42
|
+
* Payload: 100,000 nested records
|
|
43
|
+
* Input JSON size: 44.31 MiB
|
|
44
|
+
* Output XML size: 78.17 MiB
|
|
45
|
+
* Measurement: process ``ru_maxrss`` after payload creation versus peak after ``json2xml_rs.dicttoxml(payload, attr_type=True)``
|
|
46
|
+
* Sampling: three fresh Python processes per version
|
|
47
|
+
|
|
48
|
+
The baseline RSS is captured after the large Python payload is already built. The reported serializer delta is ``peak_rss - baseline_rss``, which focuses the comparison on output construction rather than payload allocation.
|
|
49
|
+
|
|
50
|
+
Raw Samples
|
|
51
|
+
-----------
|
|
52
|
+
|
|
53
|
+
.. list-table::
|
|
54
|
+
:header-rows: 1
|
|
55
|
+
:widths: 24 18 18 18 18
|
|
56
|
+
|
|
57
|
+
* - Run
|
|
58
|
+
- Baseline RSS
|
|
59
|
+
- Peak RSS
|
|
60
|
+
- Serializer delta
|
|
61
|
+
- Time
|
|
62
|
+
* - previous-release-1
|
|
63
|
+
- 191.53 MiB
|
|
64
|
+
- 349.22 MiB
|
|
65
|
+
- 157.69 MiB
|
|
66
|
+
- 0.182s
|
|
67
|
+
* - previous-release-2
|
|
68
|
+
- 191.39 MiB
|
|
69
|
+
- 349.09 MiB
|
|
70
|
+
- 157.70 MiB
|
|
71
|
+
- 0.179s
|
|
72
|
+
* - previous-release-3
|
|
73
|
+
- 191.44 MiB
|
|
74
|
+
- 349.14 MiB
|
|
75
|
+
- 157.70 MiB
|
|
76
|
+
- 0.178s
|
|
77
|
+
* - current-release-1
|
|
78
|
+
- 191.45 MiB
|
|
79
|
+
- 271.77 MiB
|
|
80
|
+
- 80.31 MiB
|
|
81
|
+
- 0.265s
|
|
82
|
+
* - current-release-2
|
|
83
|
+
- 191.48 MiB
|
|
84
|
+
- 271.64 MiB
|
|
85
|
+
- 80.16 MiB
|
|
86
|
+
- 0.272s
|
|
87
|
+
* - current-release-3
|
|
88
|
+
- 191.25 MiB
|
|
89
|
+
- 271.55 MiB
|
|
90
|
+
- 80.30 MiB
|
|
91
|
+
- 0.258s
|
|
92
|
+
|
|
93
|
+
Tradeoff
|
|
94
|
+
--------
|
|
95
|
+
|
|
96
|
+
The memory improvement comes with a throughput cost in this release benchmark. Average conversion time increased from 0.180s to 0.265s, about **47.5% slower** for this payload.
|
|
97
|
+
|
|
98
|
+
That cost is likely from routing every XML write through ``std::io::Write`` and PyO3's bytes writer. The memory win is substantial for large outputs, but latency-sensitive callers may want more timing data before treating the bytes-writer path as a universal improvement.
|
|
99
|
+
|
|
100
|
+
Reproduction
|
|
101
|
+
------------
|
|
102
|
+
|
|
103
|
+
Run each version in a fresh process after installing the desired Rust extension build.
|
|
104
|
+
|
|
105
|
+
.. code-block:: bash
|
|
106
|
+
|
|
107
|
+
python3 -m maturin develop --release --offline
|
|
108
|
+
python3 benchmark_memory_rust.py --records 100000 --label current-release-1
|
|
109
|
+
|
|
110
|
+
For the previous comparison, install commit ``7dd86b0`` in a temporary worktree, then run the same command from the main checkout so the benchmark script stays identical.
|