From 1a10b1f2204d5dadba85d8ef180171f15f40af57 Mon Sep 17 00:00:00 2001 From: Vinit Kumar Date: Mon, 18 Apr 2022 14:09:17 +0530 Subject: [PATCH] fix: return correct xml type for bool As discussed nicely in the issue https://github.com/vinitkumar/json2xml/issues/118, the correct bool value is never returned as the bool is also a subtype of numbers.Number and int. Here, hence, the check for bool is done first because while the above condition might be true for bool, no other type can say the same for bool check. i.e. Numbers won't be an instance of bool and so would be int. A test is added to guard against the future regression on this as well. - Github Issue: Resolves #118 Authored-by: Vinit Kumar Signed-off-by: Vinit Kumar --- examples/booleanjson.json | 8 ++++++++ json2xml/dicttoxml.py | 22 +++++++++++++++------- tests/test_json2xml.py | 8 ++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 examples/booleanjson.json diff --git a/examples/booleanjson.json b/examples/booleanjson.json new file mode 100644 index 00000000..a784c7b7 --- /dev/null +++ b/examples/booleanjson.json @@ -0,0 +1,8 @@ +{ + "boolean": true, + "boolean_dict_list": [ + {"boolean_dict": {"boolean": true}}, + {"boolean_dict": {"boolean": false}} + ], + "boolean_list": [true, false] +} diff --git a/json2xml/dicttoxml.py b/json2xml/dicttoxml.py index d5e3f9f4..489d55ff 100755 --- a/json2xml/dicttoxml.py +++ b/json2xml/dicttoxml.py @@ -139,6 +139,13 @@ def convert(obj, ids, attr_type, item_func, cdata, item_wrap, parent="root"): item_name = item_func(parent) + # since bool is also a subtype of number.Number and int, the check for bool + # never comes and hence we get wrong value for the xml type bool + # here, we just change order and check for bool first, because no other + # type other than bool can be true for bool check + if isinstance(obj, bool): + return convert_bool(item_name, obj, attr_type, cdata) + if isinstance(obj, (numbers.Number, str)): return convert_kv( key=item_name, val=obj, attr_type=attr_type, attr={}, cdata=cdata @@ -153,9 +160,6 @@ def convert(obj, ids, attr_type, item_func, cdata, item_wrap, parent="root"): cdata=cdata, ) - if isinstance(obj, bool): - return convert_bool(item_name, obj, attr_type, cdata) - if obj is None: return convert_none(item_name, "", attr_type, cdata) @@ -185,7 +189,14 @@ def convert_dict(obj, ids, parent, attr_type, item_func, cdata, item_wrap): key, attr = make_valid_xml_name(key, attr) - if isinstance(val, (numbers.Number, str)): + # since bool is also a subtype of number.Number and int, the check for bool + # never comes and hence we get wrong value for the xml type bool + # here, we just change order and check for bool first, because no other + # type other than bool can be true for bool check + if isinstance(val, bool): + addline(convert_bool(key, val, attr_type, attr, cdata)) + + elif isinstance(val, (numbers.Number, str)): addline( convert_kv( key=key, val=val, attr_type=attr_type, attr=attr, cdata=cdata @@ -203,9 +214,6 @@ def convert_dict(obj, ids, parent, attr_type, item_func, cdata, item_wrap): ) ) - elif isinstance(val, bool): - addline(convert_bool(key, val, attr_type, attr, cdata)) - elif isinstance(val, dict): if attr_type: attr["type"] = get_xml_type(val) diff --git a/tests/test_json2xml.py b/tests/test_json2xml.py index bbf7ae49..872ee323 100644 --- a/tests/test_json2xml.py +++ b/tests/test_json2xml.py @@ -176,3 +176,11 @@ def test_bad_data(self): with pytest.raises(InvalidDataError) as pytest_wrapped_e: json2xml.Json2xml(decoded).to_xml() assert pytest_wrapped_e.type == InvalidDataError + + def test_read_boolean_data_from_json(self): + """Test correct return for boolean types.""" + data = readfromjson("examples/booleanjson.json") + result = json2xml.Json2xml(data).to_xml() + dict_from_xml = xmltodict.parse(result) + assert dict_from_xml["all"]["boolean"]["#text"] != 'True' + assert dict_from_xml["all"]["boolean"]["#text"] == 'true'