Search code examples
pythonjsonxmlxmltodict

How to convert an xml to a dictionary with some modifications?


I currently have an xml file in the following format:

<?xml version="1.0" encoding="UTF-8" ?>
    <Garden>
        <id>97</id>
        <Flowers>
            <id>98</id>
            <Type>
                <id>99</id>
                <Level>
                    <id>100</id>                    
                </Level>
            </Type>
        </Flowers>
    </Garden>

I want to use xmltodict to convert this xml to a dictionary and that is pretty simple to do. But there is a slight modification that I would like to do.

I would like to have my json be changed to something like this.

{
    "Garden": {
        "id": "97",
        "state": "0",
        "Flowers": {
            "id": "98",
            "state": "0",
            "Type": {
                "id": "99",
                "state": "0",
                "Level": {
                    "id": "100",
                    "state": "0"                

                }
            }
        }
    }
}

I want to be able to add a default "state": "0" for all the levels. I am really confused on how to do that. Any help would be really appreciated.

This is what I have as of now:

with open("gardenlist.xml", 'r') as file:
    xmlString = file.read() 
print(xmlString)     
jsonString = json.dumps(xmltodict.parse(xmlString), indent=4)

This just prints the json but without the "state": "0" values.


Solution

  • I would say that the right way is to prepare the needed XML structure - then just convert it to dict and json string:

    Complex approach:

    import xml.etree.ElementTree as ET
    import xmltodict
    import json
    
    tree = ET.parse('gardenlist.xml')
    root = tree.getroot()
    
    state_el = ET.Element('state')    # prepare `state` node
    state_el.text = '0'
    root.insert(1, state_el)
    
    def add_state(root, el_to_insert):
        for el in root:
            if len(list(el)):    # check if element has child nodes
                el.insert(1, el_to_insert)
                add_state(el, el_to_insert)
    
    
    add_state(root, state_el)
    json_str = json.dumps(xmltodict.parse(ET.tostring(root, encoding="unicode")), indent=4)
    print(json_str)
    

    The actual output:

    {
        "Garden": {
            "id": "97",
            "state": "0",
            "Flowers": {
                "id": "98",
                "state": "0",
                "Type": {
                    "id": "99",
                    "state": "0",
                    "Level": {
                        "id": "100",
                        "state": "0"
                    }
                }
            }
        }
    }