-
-
Notifications
You must be signed in to change notification settings - Fork 32
Description
Describe the bug
When converting a JSON object with boolean type values, Json2xml
is not converting the values to their XML equivalents. Json2xml
should be exporting the values in the XML as the lowercase words true
and false
respectively. Instead, Json2xml
is exporting them as Python boolean types using the capitalized words True
and False
.
To Reproduce
Steps to reproduce the behavior:
- Given the following JSON object:
{
"boolean": true,
"boolean_dict_list": [
{"boolean_dict": {"boolean": true}},
{"boolean_dict": {"boolean": false}}
],
"boolean_list": [true, false]
}
- Calling the
Json2xml
conversion like so:
xml = json2xml.Json2xml(sample_json, pretty=True).to_xml()
- Produces the following XML:
<all>
<boolean type="bool">True</boolean>
<boolean_dict_list type="list">
<item type="dict">
<boolean_dict type="dict">
<boolean type="bool">True</boolean>
</boolean_dict>
</item>
<item type="dict">
<boolean_dict type="dict">
<boolean type="bool">False</boolean>
</boolean_dict>
</item>
</boolean_dict_list>
<item type="bool">True</item>
<item type="bool">False</item>
</all>
Notice all the boolean values are capitalized instead of being lowercase like they should be in XML and JSON. There also seems to be a problem with the boolean_list
array, it is missing its parent tag.
Expected behavior
Json2xml
should produce an XML string that looks like this:
<all>
<boolean type="bool">true</boolean>
<boolean_dict_list type="list">
<item type="dict">
<boolean_dict type="dict">
<boolean type="bool">true</boolean>
</boolean_dict>
</item>
<item type="dict">
<boolean_dict type="dict">
<boolean type="bool">false</boolean>
</boolean_dict>
</item>
</boolean_dict_list>
<boolean_list type="list">
<item type="bool">true</item>
<item type="bool">false</item>
</boolean_list>
</all>
Additional context
The problem with the capitalized boolean values is because of the following statements in the json2xml.dicttoxml
module:
def convert(obj, ids, attr_type, item_func, cdata, item_wrap, parent="root"):
"""Routes the elements of an object to the right function to convert them
based on their data type"""
LOG.info(f'Inside convert(). obj type is: "{type(obj).__name__}", obj="{str(obj)}"')
item_name = item_func(parent)
# Booleans are converted using this function because a Python boolean is a subclass of Number
if isinstance(obj, (numbers.Number, str)):
return convert_kv(
key=item_name, val=obj, attr_type=attr_type, attr={}, cdata=cdata
)
if hasattr(obj, "isoformat"):
return convert_kv(
key=item_name,
val=obj.isoformat(),
attr_type=attr_type,
attr={},
cdata=cdata,
)
# This is never evaluated because Python booleans are subclasses of Python integers
if isinstance(obj, bool):
return convert_bool(item_name, obj, attr_type, cdata)
Python booleans are subclasses of integers, so the boolean values are passed to convert_kv
instead of convert_bool
because an integer is also a numbers.Number
. The following statements evaluate to True
in Python:
# Booleans are integers
isinstance(True, int)
# Booleans are numbers
isinstance(True, numbers.Number)
# Booleans are booleans
isinstance(True, bool)