xmltodict-rs 0.13.0__cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
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.
- xmltodict_rs/__init__.py +9 -0
- xmltodict_rs/__init__.pyi +140 -0
- xmltodict_rs/py.typed +0 -0
- xmltodict_rs/xmltodict_rs.cpython-312-powerpc64le-linux-gnu.so +0 -0
- xmltodict_rs-0.13.0.dist-info/METADATA +179 -0
- xmltodict_rs-0.13.0.dist-info/RECORD +8 -0
- xmltodict_rs-0.13.0.dist-info/WHEEL +5 -0
- xmltodict_rs-0.13.0.dist-info/licenses/LICENSE +21 -0
xmltodict_rs/__init__.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""xmltodict_rs - High-performance XML to dict conversion library using Rust and PyO3.
|
|
2
|
+
|
|
3
|
+
This module provides parse() and unparse() functions for converting between
|
|
4
|
+
XML and Python dictionaries with better performance than pure Python implementations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .xmltodict_rs import parse, unparse
|
|
8
|
+
|
|
9
|
+
__all__ = ["parse", "unparse"]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Type stubs for xmltodict_rs - High-performance XML to dict conversion library.
|
|
2
|
+
|
|
3
|
+
This module provides a Rust-based implementation of xmltodict functionality
|
|
4
|
+
with full type annotations for better IDE support and type checking.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from collections.abc import Collection
|
|
8
|
+
from typing import Any, Callable
|
|
9
|
+
|
|
10
|
+
XMLInput = str | bytes
|
|
11
|
+
XMLDict = dict[str, Any]
|
|
12
|
+
PostprocessorFunc = Callable[[list[str], str, Any], tuple[str, Any] | None]
|
|
13
|
+
PreprocessorFunc = Callable[[str, Any], tuple[str, Any] | None]
|
|
14
|
+
|
|
15
|
+
def parse(
|
|
16
|
+
xml_input: XMLInput,
|
|
17
|
+
encoding: str | None = None,
|
|
18
|
+
process_namespaces: bool = False,
|
|
19
|
+
namespace_separator: str = ":",
|
|
20
|
+
disable_entities: bool = True,
|
|
21
|
+
process_comments: bool = False,
|
|
22
|
+
xml_attribs: bool = True,
|
|
23
|
+
attr_prefix: str = "@",
|
|
24
|
+
cdata_key: str = "#text",
|
|
25
|
+
force_cdata: bool = False,
|
|
26
|
+
cdata_separator: str = "",
|
|
27
|
+
strip_whitespace: bool = True,
|
|
28
|
+
force_list: bool | Collection[str] | Callable[[list[str], str, Any], bool] | None = None,
|
|
29
|
+
postprocessor: PostprocessorFunc | None = None,
|
|
30
|
+
item_depth: int = 0,
|
|
31
|
+
comment_key: str = "#comment",
|
|
32
|
+
namespaces: dict[str, str] | None = None,
|
|
33
|
+
) -> XMLDict:
|
|
34
|
+
"""Parse XML string or bytes into a Python dictionary.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
xml_input: XML data as string or bytes to parse
|
|
38
|
+
encoding: Character encoding (for compatibility, not used in Rust implementation)
|
|
39
|
+
process_namespaces: If True, namespace prefixes are processed and expanded
|
|
40
|
+
namespace_separator: Separator character between namespace and tag name (default ':')
|
|
41
|
+
disable_entities: If True, XML entities are disabled for security (default True)
|
|
42
|
+
process_comments: If True, XML comments are included in output with comment_key
|
|
43
|
+
xml_attribs: If True, XML attributes are included in output (default True)
|
|
44
|
+
attr_prefix: Prefix for attribute keys in output dict (default '@')
|
|
45
|
+
cdata_key: Key name for text content in output dict (default '#text')
|
|
46
|
+
force_cdata: If True, text content is always wrapped in dict with cdata_key
|
|
47
|
+
cdata_separator: Separator for multiple text nodes (default '')
|
|
48
|
+
strip_whitespace: If True, whitespace-only text is removed (default True)
|
|
49
|
+
force_list: Control when to create lists for repeated elements:
|
|
50
|
+
- None/False: automatic list creation for repeated elements
|
|
51
|
+
- True: always create lists
|
|
52
|
+
- set/list: create lists for specified tag names
|
|
53
|
+
- Callable: custom function (path, key, value) -> bool
|
|
54
|
+
postprocessor: Optional callback to transform parsed data:
|
|
55
|
+
- Called with (path, key, value)
|
|
56
|
+
- Should return (new_key, new_value) tuple or None to skip
|
|
57
|
+
item_depth: Internal parameter for tracking parsing depth
|
|
58
|
+
comment_key: Key name for XML comments in output (default '#comment')
|
|
59
|
+
namespaces: Optional dict mapping namespace URIs to prefixes
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Dictionary representation of the XML structure
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
ValueError: If XML is malformed or has parsing errors
|
|
66
|
+
TypeError: If xml_input is not str or bytes
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
>>> parse('<root><item>value</item></root>')
|
|
70
|
+
{'root': {'item': 'value'}}
|
|
71
|
+
|
|
72
|
+
>>> parse('<root id="1"><item>A</item><item>B</item></root>')
|
|
73
|
+
{'root': {'@id': '1', 'item': ['A', 'B']}}
|
|
74
|
+
|
|
75
|
+
>>> parse('<root>text</root>', force_cdata=True)
|
|
76
|
+
{'root': {'#text': 'text'}}
|
|
77
|
+
|
|
78
|
+
>>> def postproc(path, key, value):
|
|
79
|
+
... return (key.upper(), value)
|
|
80
|
+
>>> parse('<root><item>value</item></root>', postprocessor=postproc)
|
|
81
|
+
{'ROOT': {'ITEM': 'value'}}
|
|
82
|
+
"""
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
def unparse(
|
|
86
|
+
input_dict: XMLDict,
|
|
87
|
+
output: str | None = None,
|
|
88
|
+
encoding: str = "utf-8",
|
|
89
|
+
full_document: bool = True,
|
|
90
|
+
short_empty_elements: bool = False,
|
|
91
|
+
attr_prefix: str = "@",
|
|
92
|
+
cdata_key: str = "#text",
|
|
93
|
+
pretty: bool = False,
|
|
94
|
+
newl: str = "\n",
|
|
95
|
+
indent: str = "\t",
|
|
96
|
+
preprocessor: PreprocessorFunc | None = None,
|
|
97
|
+
) -> str:
|
|
98
|
+
r"""Convert Python dictionary back to XML string.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
input_dict: Dictionary to convert to XML (must have exactly one root key if full_document=True)
|
|
102
|
+
output: Optional file-like object to write to (for compatibility, returns string anyway)
|
|
103
|
+
encoding: Character encoding for XML declaration (default 'utf-8')
|
|
104
|
+
full_document: If True, includes XML declaration (default True)
|
|
105
|
+
short_empty_elements: If True, empty elements use <tag/> format (default False)
|
|
106
|
+
attr_prefix: Prefix used to identify attribute keys (default '@')
|
|
107
|
+
cdata_key: Key name that contains text content (default '#text')
|
|
108
|
+
pretty: If True, output is formatted with indentation (default False)
|
|
109
|
+
newl: Newline character for pretty printing (default '\n')
|
|
110
|
+
indent: Indentation string for pretty printing (default '\t')
|
|
111
|
+
preprocessor: Optional callback to transform data before unparsing:
|
|
112
|
+
- Called with (key, value)
|
|
113
|
+
- Should return (new_key, new_value) tuple or None to skip
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
XML string representation of the dictionary
|
|
117
|
+
|
|
118
|
+
Raises:
|
|
119
|
+
ValueError: If full_document=True and dict doesn't have exactly one root element
|
|
120
|
+
TypeError: If input_dict is not a dictionary
|
|
121
|
+
|
|
122
|
+
Examples:
|
|
123
|
+
>>> unparse({'root': {'item': 'value'}})
|
|
124
|
+
'<?xml version="1.0" encoding="utf-8"?>\\n<root><item>value</item></root>'
|
|
125
|
+
|
|
126
|
+
>>> unparse({'root': {'@id': '1', 'item': 'value'}})
|
|
127
|
+
'<?xml version="1.0" encoding="utf-8"?>\\n<root id="1"><item>value</item></root>'
|
|
128
|
+
|
|
129
|
+
>>> unparse({'root': None}, short_empty_elements=True)
|
|
130
|
+
'<?xml version="1.0" encoding="utf-8"?>\\n<root/>'
|
|
131
|
+
|
|
132
|
+
>>> unparse({'root': {'item': ['A', 'B']}})
|
|
133
|
+
'<?xml version="1.0" encoding="utf-8"?>\\n<root><item>A</item><item>B</item></root>'
|
|
134
|
+
|
|
135
|
+
>>> unparse({'root': {'child': 'value'}}, pretty=True)
|
|
136
|
+
'<?xml version="1.0" encoding="utf-8"?>\\n<root>\\n\\t<child>value</child>\\n</root>'
|
|
137
|
+
"""
|
|
138
|
+
...
|
|
139
|
+
|
|
140
|
+
__all__ = ["parse", "unparse"]
|
xmltodict_rs/py.typed
ADDED
|
File without changes
|
|
Binary file
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xmltodict-rs
|
|
3
|
+
Version: 0.13.0
|
|
4
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
5
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
6
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
10
|
+
Classifier: Typing :: Typed
|
|
11
|
+
Classifier: Programming Language :: Rust
|
|
12
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
13
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Summary: High-performance XML to dict conversion library using Rust and PyO3
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
18
|
+
Project-URL: Homepage, https://github.com/tochka-public/xmltodict_rs
|
|
19
|
+
Project-URL: Repository, https://github.com/tochka-public/xmltodict_rs
|
|
20
|
+
Project-URL: Issues, https://github.com/tochka-public/xmltodict_rs/issues
|
|
21
|
+
|
|
22
|
+
# xmltodict_rs
|
|
23
|
+
|
|
24
|
+
High-performance XML to dict conversion library using Rust and PyO3
|
|
25
|
+
|
|
26
|
+
A Rust-based implementation of `xmltodict` that provides significant performance improvements while maintaining API compatibility.
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- **High Performance** - 5-10x faster than pure Python implementation
|
|
31
|
+
- **Full Compatibility** - Drop-in replacement for `xmltodict`
|
|
32
|
+
- **Type Safe** - Includes comprehensive type stubs (`.pyi` files) for better IDE support
|
|
33
|
+
- **Safe** - Built with Rust for memory safety and security
|
|
34
|
+
- **Easy to Use** - Simple installation and familiar API
|
|
35
|
+
|
|
36
|
+
## Versioning
|
|
37
|
+
|
|
38
|
+
The major and minor version numbers of `xmltodict_rs` match those of the original `xmltodict` library. This ensures that the behavior is consistent with the corresponding version of `xmltodict`, making it a true drop-in replacement. Patch versions may differ for Rust-specific fixes and optimizations.
|
|
39
|
+
|
|
40
|
+
For example:
|
|
41
|
+
- `xmltodict_rs 0.13.x` matches the behavior of `xmltodict 0.13.x`
|
|
42
|
+
- `xmltodict_rs 0.14.x` matches the behavior of `xmltodict 0.14.x`
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install xmltodict-rs
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or with uv:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv add xmltodict-rs
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import xmltodict_rs
|
|
60
|
+
|
|
61
|
+
# Parse XML to dictionary
|
|
62
|
+
xml = '<root><item id="1">value</item></root>'
|
|
63
|
+
result = xmltodict_rs.parse(xml)
|
|
64
|
+
print(result)
|
|
65
|
+
# {'root': {'item': {'@id': '1', '#text': 'value'}}}
|
|
66
|
+
|
|
67
|
+
# Convert dictionary back to XML
|
|
68
|
+
data = {'root': {'item': 'value'}}
|
|
69
|
+
xml = xmltodict_rs.unparse(data)
|
|
70
|
+
print(xml)
|
|
71
|
+
# <?xml version="1.0" encoding="utf-8"?>
|
|
72
|
+
# <root><item>value</item></root>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Type Hints Support
|
|
76
|
+
|
|
77
|
+
Full type annotations are included for better IDE support and static type checking:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from typing import Any
|
|
81
|
+
import xmltodict_rs
|
|
82
|
+
|
|
83
|
+
# IDE will provide autocomplete and type checking
|
|
84
|
+
result: dict[str, Any] = xmltodict_rs.parse("<root><item>test</item></root>")
|
|
85
|
+
|
|
86
|
+
# Type checkers like mypy will catch errors
|
|
87
|
+
xmltodict_rs.parse(123) # Error: Expected str or bytes
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## API Reference
|
|
92
|
+
|
|
93
|
+
### parse()
|
|
94
|
+
|
|
95
|
+
Convert XML to a Python dictionary.
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
xmltodict_rs.parse(
|
|
99
|
+
xml_input, # str or bytes: XML data to parse
|
|
100
|
+
process_namespaces=False, # bool: Process namespace prefixes
|
|
101
|
+
namespace_separator=":", # str: Separator for namespace and tag
|
|
102
|
+
disable_entities=True, # bool: Disable XML entities for security
|
|
103
|
+
process_comments=False, # bool: Include XML comments in output
|
|
104
|
+
xml_attribs=True, # bool: Include attributes in output
|
|
105
|
+
attr_prefix="@", # str: Prefix for attribute keys
|
|
106
|
+
cdata_key="#text", # str: Key name for text content
|
|
107
|
+
force_cdata=False, # bool: Always wrap text in dict
|
|
108
|
+
cdata_separator="", # str: Separator for multiple text nodes
|
|
109
|
+
strip_whitespace=True, # bool: Remove whitespace-only text
|
|
110
|
+
force_list=None, # Control list creation
|
|
111
|
+
postprocessor=None, # Callback for transforming data
|
|
112
|
+
item_depth=0, # Internal depth tracking
|
|
113
|
+
comment_key="#comment", # str: Key name for comments
|
|
114
|
+
namespaces=None # dict: Namespace URI mapping
|
|
115
|
+
)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### unparse()
|
|
119
|
+
|
|
120
|
+
Convert a Python dictionary back to XML.
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
xmltodict_rs.unparse(
|
|
124
|
+
input_dict, # dict: Dictionary to convert
|
|
125
|
+
encoding="utf-8", # str: Character encoding
|
|
126
|
+
full_document=True, # bool: Include XML declaration
|
|
127
|
+
short_empty_elements=False, # bool: Use <tag/> for empty elements
|
|
128
|
+
attr_prefix="@", # str: Prefix identifying attributes
|
|
129
|
+
cdata_key="#text", # str: Key containing text content
|
|
130
|
+
pretty=False, # bool: Format with indentation
|
|
131
|
+
newl="\n", # str: Newline character
|
|
132
|
+
indent="\t", # str: Indentation string
|
|
133
|
+
preprocessor=None # Callback for transforming data
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Performance
|
|
138
|
+
|
|
139
|
+
Based on benchmarks with various XML sizes:
|
|
140
|
+
|
|
141
|
+
| Operation | Small (0.3KB) | Medium (15KB) | Large (150KB) |
|
|
142
|
+
|-----------|---------------|---------------|---------------|
|
|
143
|
+
| Parse | ~8x faster | ~6x faster | ~5x faster |
|
|
144
|
+
| Unparse | ~10x faster | ~8x faster | ~7x faster |
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
### Setup
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Install dependencies
|
|
153
|
+
uv venv
|
|
154
|
+
uv sync
|
|
155
|
+
|
|
156
|
+
# Build the Rust extension
|
|
157
|
+
just dev
|
|
158
|
+
|
|
159
|
+
# Run tests
|
|
160
|
+
just test
|
|
161
|
+
|
|
162
|
+
# Run benchmarks
|
|
163
|
+
uv run python benches/accurate_benchmark.py
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Contributing
|
|
167
|
+
|
|
168
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
169
|
+
|
|
170
|
+
1. Fork the repository
|
|
171
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
172
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
173
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
174
|
+
5. Open a Pull Request
|
|
175
|
+
|
|
176
|
+
## Links
|
|
177
|
+
|
|
178
|
+
- [Original xmltodict](https://github.com/martinblech/xmltodict)
|
|
179
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
xmltodict_rs-0.13.0.dist-info/METADATA,sha256=T0ohHLCcA1oY0oB1LkorJDK6f6EGjdRCtig1qsBV5Tk,5785
|
|
2
|
+
xmltodict_rs-0.13.0.dist-info/WHEEL,sha256=r3Re1LyxSX0vTMvaekQJYIADPZ3YvOvqupg0m4KOsyk,149
|
|
3
|
+
xmltodict_rs-0.13.0.dist-info/licenses/LICENSE,sha256=TejyJYC8dHf16Vx7Okwl2PQhaPEutztvHPh0TKJ1xrA,1075
|
|
4
|
+
xmltodict_rs/__init__.py,sha256=HOypcbSGzLktZ4OZzYE1L9SvJr1Z-W80qBzxkhzhMYo,328
|
|
5
|
+
xmltodict_rs/__init__.pyi,sha256=kZcbEjWwep26f2Isi_g_XLqg_lm1ntkj99NRw0OLQgU,6052
|
|
6
|
+
xmltodict_rs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
xmltodict_rs/xmltodict_rs.cpython-312-powerpc64le-linux-gnu.so,sha256=moUKGPQvPfgrdkTPyJHBMWcj6vRRl7sXCa0ww7_Fhbs,529320
|
|
8
|
+
xmltodict_rs-0.13.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Точка Банк
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|