convert-dict-xml
Convert Python dicts to XML and back using lxml. Supports attributes and CDATA.
Features
- Dict to XML — supports nested dicts, attributes, CDATA sections, and lists of sibling elements
- XML to Dict — parse XML back into plain dicts or
OrderedDict - Type serialization —
bool,None,datetimehandled automatically - Round-trip — convert dict → XML → dict
Installation
pip install convert-dict-xml
Note: Requires lxml, which needs
libxml2andlibxsltsystem libraries on some platforms.
Quick Start
Dict to XML
from convert_dict_xml import Dict2XML
data = {
'@attributes': {'type': 'fiction'},
'book': ['1984', 'Foundation']
}
xml = Dict2XML('books', data).to_xml_string(xml_declaration=False)
print(xml.decode())
<books type="fiction">
<book>1984</book>
<book>Foundation</book>
</books>
XML to Dict
from convert_dict_xml import XML2Dict
result = XML2Dict(xml).to_dict()
# {'@attributes': {'type': 'fiction'}, 'book': ['1984', 'Foundation']}
For namespaced XML, use strip_namespaces=True to get clean dict keys:
xml = b'<feed xmlns="http://www.w3.org/2005/Atom"><title>Blog</title></feed>'
result = XML2Dict(xml, strip_namespaces=True).to_dict()
# {'title': 'Blog'}
Dict Conventions
Use special keys to control XML output:
| Key | Purpose | Example |
|---|---|---|
@attributes |
Set XML attributes | {'@attributes': {'id': '1'}} → <node id="1"/> |
@text |
Set text content | {'@text': 'hello'} → <node>hello</node> |
@cdata |
Wrap text in CDATA | {'@cdata': 'hello'} → <node><![CDATA[hello]]></node> |
| (list value) | Sibling elements | {'item': ['a', 'b']} → <item>a</item><item>b</item> |
Use force_cdata=True to wrap all text nodes in CDATA sections.
Text Nodes
Text can be set directly or via @text:
books = {'book': 1984}
# or
books = {'book': {'@text': 1984}}
xml = Dict2XML('books', books).to_xml_string(xml_declaration=False)
print(xml.decode())
<books>
<book>1984</book>
</books>
Attributes
books = {
'@attributes': {'type': 'fiction'},
'book': 1984
}
xml = Dict2XML('books', books).to_xml_string(xml_declaration=False)
print(xml.decode())
<books type="fiction">
<book>1984</book>
</books>
Multiple Children
Lists produce sibling elements with the same tag:
books = {
'@attributes': {'type': 'fiction'},
'book': ['1984', 'Foundation', 'Stranger in a Strange Land']
}
xml = Dict2XML('books', books).to_xml_string(xml_declaration=False)
print(xml.decode())
<books type="fiction">
<book>1984</book>
<book>Foundation</book>
<book>Stranger in a Strange Land</book>
</books>
CDATA
books = {
'book': [
{'title': '1984', 'isbn': 973534},
{'title': {'@cdata': 'Foundation'}, 'price': '$15.61', 'isbn': 573234},
]
}
xml = Dict2XML('books', books).to_xml_string(xml_declaration=False)
print(xml.decode())
<books>
<book>
<isbn>973534</isbn>
<title>1984</title>
</book>
<book>
<price>$15.61</price>
<isbn>573234</isbn>
<title><![CDATA[Foundation]]></title>
</book>
</books>
Complex Example
from collections import OrderedDict
from convert_dict_xml import Dict2XML
books = OrderedDict({
'@attributes': {'type': 'fiction'},
'book': [
{
'@attributes': {'author': 'George Orwell', 'available': None},
'title': '1984',
'isbn': 972132,
},
{
'@attributes': {'author': 'Isaac Asimov', 'available': False},
'title': {'@cdata': 'Foundation'},
'price': '$15.61',
'isbn': 5735232,
},
{
'@attributes': {'author': 'Robert A Heinlein', 'available': True},
'title': {'@cdata': 'Stranger in a Strange Land'},
'price': {'@attributes': {'discount': '10%'}, '@text': '$18.00'},
'isbn': 3412332,
},
],
})
xml = Dict2XML('books', books).to_xml_string(xml_declaration=False)
print(xml.decode()
<books type="fiction">
<book available="" author="George Orwell">
<isbn>972132</isbn>
<title>1984</title>
</book>
<book available="false" author="Isaac Asimov">
<price>$15.61</price>
<isbn>5735232</isbn>
<title><![CDATA[Foundation]]></title>
</book>
<book available="true" author="Robert A Heinlein">
<price discount="10%">$18.00</price>
<isbn>3412332</isbn>
<title><![CDATA[Stranger in a Strange Land]]></title>
</book>
</books>
API Reference
Dict2XML(root_node_name, dictionary, force_cdata=False)
| Parameter | Description |
|---|---|
root_node_name |
Name of the root XML element |
dictionary |
The dict to convert |
force_cdata |
Wrap all text nodes in CDATA sections (default False) |
| Method | Returns |
|---|---|
to_xml_string(encoding='UTF-8', pretty_print=True, xml_declaration=True) |
XML as bytes |
get_etree_object() |
The underlying lxml.etree.Element |
XML2Dict(xml, ns_clean=True, strip_namespaces=False)
| Parameter | Description |
|---|---|
xml |
XML string or bytes to parse |
ns_clean |
Clean up redundant namespace declarations (default True) |
strip_namespaces |
Remove namespace URIs from tag names in the output dict (default False) |
| Method | Returns |
|---|---|
to_dict(ordered_dict=False) |
dict (or OrderedDict if ordered_dict=True) |
get_etree_object() |
The underlying lxml.etree.Element |
Contributing
git clone https://github.com/lalitpatel/convert-dict-xml.git
cd convert-dict-xml
pip install -e ".[dev]"
pytest
License
MIT — Copyright (c) 2018 Lalit Patel
Metadata
Release files for convert-dict-xml 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| convert_dict_xml-1.0.0.tar.gz | 10.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| convert_dict_xml-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.0 kB
Release files / convert_dict_xml-1.0.0.tar.gz
| Download URL | convert_dict_xml-1.0.0.tar.gz |
|---|---|
| Size | 10.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a37bb22ac2743b25ee9c366c499d0e44d0ba5178573b77002eabf2bbbff8451e
|
|
BLAKE2b-256 checksum How to use checksums |
c113aee8c9470375b9b05861fe0dee302f5adbbe377a6e3b640d05ad9345677e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 3, 2026.
Transparency logRelease files / convert_dict_xml-1.0.0-py3-none-any.whl
| Download URL | convert_dict_xml-1.0.0-py3-none-any.whl |
|---|---|
| Size | 6.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5f79cfb0c281a4659fe85a190326a7288fce4ca5088c86052c01177d6ebac2ed
|
|
BLAKE2b-256 checksum How to use checksums |
d88a1a90ea343f0c49d02319c1668d5a4888098efca894d664560b57baf7560a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 3, 2026.
Transparency log