Home > Enterprise >  How to convert JSON to XML using python?
How to convert JSON to XML using python?

Time:02-18

i need to convert a JSON file

{
"Order1/variable1.py": {
    "Order1/variable1.py": null,
    "Order1/variable2.py": 7,
    "Order1/variable3.py": 23,
    "Order2/variable4.py": 61,
    "Order2/variable5.py": 0,
},
"Order1/variable2.py": {
    "Order1/variable1.py": 100,
    "Order1/variable2.py": null,
    "Order1/variable3.py": 35,
    "Order2/variable4.py": 13,
    "Order2/variable5.py": 0,
},
"Order1/variable3.py": {
    "Order1/variable1.py": 18,
    "Order1/variable2.py": 24,
    "Order1/variable3.py": null,
    "Order2/variable4.py": 0,
    "Order2/variable5.py": 0,
},
"Order2/variable4.py": {
    "Order1/variable1.py": 6,
    "Order1/variable2.py": 72,
    "Order1/variable3.py": 39,
    "Order2/variable4.py": null,
    "Order2/variable5.py": 0,
},
"Order2/variable5.py": {
    "Order1/variable1.py": 0,
    "Order1/variable2.py": 71,
    "Order1/variable3.py": 88,
    "Order2/variable4.py": 69,
    "Order2/variable5.py": null,
},}

into an XML file that must look like this

<?xml version="1.0" encoding="utf-8"?>
<model elementCount="7" relationCount="20">
  <elements>
    <element id="2" order="2" name="Order1" type="Order" expanded="True" />
    <element id="3" order="3" name="variable1" type="Variable" expanded="False" parent="2" />
    <element id="4" order="4" name="variable2" type="Variable" expanded="False" parent="2" />
    <element id="5" order="5" name="variable3" type="Variable" expanded="False" parent="2" />
    <element id="6" order="6" name="Order2" type="Order" expanded="True" />
    <element id="7" order="7" name="variable4" type="Variable" expanded="False" parent="6" />
    <element id="8" order="8" name="variable5" type="Variable" expanded="False" parent="6" />

  </elements>
  <relations>
    <relation id="1" from="3" to="4" type="" weight="7" />
    <relation id="2" from="3" to="5" type="" weight="23" />
    <relation id="3" from="3" to="7" type="" weight="61" />
    <relation id="4" from="3" to="8" type="" weight="0" />
    <relation id="5" from="4" to="3" type="" weight="100" />
    <relation id="6" from="4" to="5" type="" weight="35" />
    <relation id="7" from="4" to="7" type="" weight="13" />
    <relation id="8" from="4" to="8" type="" weight="0" />
    <relation id="9" from="5" to="3" type="" weight="18" />
    <relation id="10" from="5" to="4" type="" weight="24" />
    <relation id="11" from="5" to="7" type="" weight="0" />
    <relation id="12" from="5" to="8" type="" weight="0" />
    <relation id="13" from="7" to="3" type="" weight="6" />
    <relation id="14" from="7" to="4" type="" weight="72" />
    <relation id="15" from="7" to="5" type="" weight="39" />
    <relation id="16" from="7" to="8" type="" weight="0" />
    <relation id="17" from="8" to="3" type="" weight="0" />
    <relation id="18" from="8" to="4" type="" weight="71" />
    <relation id="19" from="8" to="5" type="" weight="88" />
    <relation id="20" from="8" to="7" type="" weight="69" />
  </relations>
</model>

The JSON file will always be in that format since it comes from another tool, but it may contain more elements (Orders or variables) and therefore each variable would have more rows (e.g., the element Order1/variable1.py may contain some more value like "Order3/variable6.py": 25,).

The XML file also must to be in the format from this example, but the "relations" with weight = 0 may be ignored.

Since i am very new to this topic, i have no idea how to convert it and would be very grateful for any advices.

*I must realize it using python

CodePudding user response:

I made this script to convert your JSON to XML. I haven't tried some particular cases of JSON, but you can still use it as a base.

import json


with open('json_data.json', 'r') as f:
    data = json.load(f)

xml_dict = {}
for key in data:
    order, variable = key.split("/")
    variable = variable.replace(".py", "")
    if order not in xml_dict:
        xml_dict[order] = [variable]
    else:
        xml_dict[order].append(variable)

xml = '<elements>'
object_id = []
for key in xml_dict:
    order_index = len(object_id)   2
    xml  = f'<element id="{order_index}" order="{order_index}" name="{key}" type="Order" expanded="True" />'
    object_id.append(key)
    for variable in xml_dict[key]:
        xml  = f'<element id="{len(object_id)   2}" order="{len(object_id)   2}" name="{variable}" type="Variable" expanded="False" parent="{order_index}" />'
        object_id.append(variable)
xml  = '</elements>'

xml  = '<relations>'
index = 0
for key in data:
    index_from = object_id.index(key.split('/')[1].replace('.py', ''))   2
    for relation in data[key]:
        if data[key][relation] is not None:
            index_to = object_id.index(relation.split('/')[1].replace('.py', ''))   2
            xml  = f'<relation id="{index   1}" from="{index_from}" to="{index_to}" type="" weight="{data[key][relation]}" />'
            index  = 1
xml  = '</relations>'

xml = f'<?xml version="1.0" encoding="utf-8"?><model elementCount="{len(object_id)}" relationCount="{index}">'   xml   '</model>'

with open('xml_data.xml', 'w') as f:
    f.write(xml)

CodePudding user response:

Not beautiful nor optimised but working on your example.

import json
# read the json
with open("test.json") as f:
    data = json.load(f)

# count elements
element_count = len(data)
relation_count = sum([len(relations) for relations in data.values()])

# Create high level hierarchy
import xml.etree.ElementTree as ET
root = ET.Element("model", {"elementCount": str(element_count), "relationCount": str(relation_count)})
elements = ET.SubElement(root, "elements")
relations = ET.SubElement(root, "relations")

# Create the architecture to know what element is expanded or not and their relations.
elements_arch = {}
for element in data:
    splitted = element.split("/")
    parent = splitted[0]
    child = splitted[1].split(".")[0]
    if parent in elements_arch:
        elements_arch[parent].append(child)
    else:
        elements_arch[parent] = [child]


# Create all elements and keep record of the matching between name and element_id
element_id = 0
element_to_id = {}
for order, variables in elements_arch.items():
    ET.SubElement(elements, "element", {"id": str(element_id), "name": order,"order": str(element_id), "type": "Order", "expended": "True"})
    parent_id = element_id
    element_to_id[order] = str(element_id)
    element_id  = 1
    for child in variables:
        ET.SubElement(elements, "element", {"id": str(element_id),"name": child, "order": str(element_id), "type": "Variable", "expended": "True", "parent": str(parent_id)})
        element_to_id[child] = str(element_id)
        element_id  = 1

# Create relations
relation_id = 0
for relation_list in data.values():
    for relation, weight in relation_list.items():
        splitted = relation.split("/")
        parent = splitted[0]
        child = splitted[1].split(".")[0]
        if weight is not None:
            ET.SubElement(relations, "relation", {"id": str(relation_id), "from": element_to_id[parent], "to": element_to_id[child], "type": "", "weight": str(weight)})

# Make the XML pretty (Works on Python 3.9, not on <3.7, don't know for 3.8)
ET.indent(root)

# Save to XML file
tree = ET.ElementTree(root)
tree.write("test_parsing.xml")
  • Related