Dictify — XML to Dict¶
pygixml.dictify converts XML to a nested Python dict, fully
compatible with the xmltodict
library. Drop import xmltodict and replace it with
from pygixml import dictify — the API is identical.
from pygixml import dictify
xml = """
<database name="users_db" version="1.2">
<user-profile id="101" verified="true">
<first_name>Mohammad</first_name>
<balance>450.75</balance>
</user-profile>
<entry>Value A</entry>
<entry>Value B</entry>
</database>
"""
d = dictify.parse(xml)
# {
# 'database': {
# '@name': 'users_db',
# '@version': '1.2',
# 'user-profile': {
# '@id': '101', '@verified': 'true',
# 'first_name': 'Mohammad', 'balance': '450.75'
# },
# 'entry': ['Value A', 'Value B']
# }
# }
# Repeated siblings are automatically collapsed into a list
d['database']['entry'] # ['Value A', 'Value B']
# Attributes are prefixed with '@'
d['database']['@name'] # 'users_db'
# Convert back to XML
xml_out = dictify.unparse(d, pretty=True)
Entry Points¶
- pygixml.dictify.parse(xml, attr_prefix='@', cdata_key='#text', force_list=None, encoding=None)
Parse an XML string into a nested dict.
- Parameters:
xml (str) – XML source text.
attr_prefix (str) – Prefix prepended to attribute keys. Default
"@".cdata_key (str) – Key used for text content in mixed nodes. Default
"#text".force_list (set or True or None) – Tag names that should always be wrapped in a list even when only one element exists. Pass
Trueto force all tags.encoding – Accepted for API compatibility; ignored (pygixml auto-detects encoding).
- Returns:
Parsed document as a nested dict.
- Return type:
dict
- Raises:
PygiXMLError – If the XML is malformed.
# Default — attributes prefixed with '@' d = dictify.parse('<root id="1"><item>x</item></root>') # {'root': {'@id': '1', 'item': 'x'}} # Custom prefix d = dictify.parse('<root id="1">text</root>', attr_prefix='', cdata_key='text') # {'root': {'id': '1', 'text': 'text'}} # Force single element into a list d = dictify.parse('<root><x>only</x></root>', force_list={'x'}) # {'root': {'x': ['only']}}
- pygixml.dictify.parse_file(path, attr_prefix='@', cdata_key='#text', force_list=None)
Parse an XML file into a nested dict. Accepts the same keyword arguments as
parse().- Parameters:
path (str) – Filesystem path to the XML file.
- Raises:
PygiXMLError – If the file cannot be read or the XML is malformed.
- pygixml.dictify.unparse(input_dict, output=None, encoding='utf-8', full_document='true', indent='\\t', attr_prefix='@', cdata_key='#text', pretty=False)
Emit an XML string from a dict produced by
parse().- Parameters:
input_dict (dict) – A
{root_tag: value}dict.encoding (str) – Encoding declared in the XML header. Default
"utf-8".full_document (str) –
"true"to include the XML declaration line.indent (str) – Indentation string when pretty is
True. Default tab.attr_prefix (str) – Prefix that identifies attribute keys. Default
"@".cdata_key (str) – Key holding text content. Default
"#text".pretty (bool) – Whether to indent output. Default
False.
- Returns:
XML string.
- Return type:
str
- Raises:
ValueError – If input_dict does not have exactly one root key.
d = {'root': {'@id': '1', 'item': ['a', 'b']}} print(dictify.unparse(d, pretty=True)) # <?xml version="1.0" encoding="utf-8"?> # <root id="1"> # <item>a</item> # <item>b</item> # </root>
Conversion Rules¶
The conversion rules match the xmltodict library exactly:
XML structure |
Dict representation |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
Text content |
Note
Unlike pygixml.objectify, dictify does not perform type
inference — all values remain as strings, exactly as xmltodict behaves.
This preserves round-trip fidelity with unparse().
force_list¶
By default, a tag that appears only once is stored as a scalar value. Use
force_list to always produce a list — useful when your code always expects
a list regardless of how many elements are present:
xml = '<catalog><item>only one</item></catalog>'
# Without force_list — scalar
d = dictify.parse(xml)
d['catalog']['item'] # 'only one' (str)
# With force_list — always a list
d = dictify.parse(xml, force_list={'item'})
d['catalog']['item'] # ['only one'] (list)
# Force ALL tags into lists
d = dictify.parse(xml, force_list=True)
d['catalog']['item'] # ['only one']
Round-trip¶
parse() and unparse() are
round-trip compatible — parsing the output of unparse produces the same
dict:
original_xml = '<root id="1"><items><item>a</item><item>b</item></items></root>'
d = dictify.parse(original_xml)
xml2 = dictify.unparse(d)
d2 = dictify.parse(xml2)
assert d == d2 # ✓
Comparison with objectify¶
Feature |
|
|
|---|---|---|
Access style |
|
|
Type inference |
Yes — |
No — all values are |
Repeated siblings |
|
Python |
Memory |
Wraps the live DOM — no copy |
Full copy into Python dicts |
Best for |
Navigating and reading XML |
Serialising XML to JSON / passing to APIs |