-1

I need to generate a JSON file with no root element. however, I manage to generate an XML without the tag. I do not want my JSON with the { "root": element.

XML:

<dataSources>
    <xid>DS_000001</xid>
    <type>MODBUS_IP</type>
    <updatePeriodType>MILLISECONDS</updatePeriodType>
    <transportType>TCP</transportType>
    <host>123.456.78.11</host>
    <name>test1</name>
    <port>502</port>
    <updatePeriods>500</updatePeriods>
</dataSources>
<dataSources>
    <xid>DS_000002</xid>
    <type>MODBUS_IP</type>
    <updatePeriodType>MILLISECONDS</updatePeriodType>
    <transportType>TCP</transportType>
    <host>123.456.78.12</host>
    <name>test2</name>
    <port>502</port>
    <updatePeriods>500</updatePeriods>
</dataSources>

<dataPoints>
    <xid>DP_000001</xid>
    <pointLocator>
        <range>HOLDING_REGISTER</range>
        <modbusDataType>FOUR_BYTE_FLOAT</modbusDataType>
        <offset>2848</offset>
    </pointLocator>
    <engineeringUnits/>
    <dataSourceXid>DS_000001</dataSourceXid>
    <deviceName>test1</deviceName>
    <name>line_load_percent00</name>
</dataPoints>

<dataPoints>
    <xid>DP_000002</xid>
    <pointLocator>
        <range>HOLDING_REGISTER</range>
        <modbusDataType>FOUR_BYTE_FLOAT</modbusDataType>
        <offset>2850</offset>
    </pointLocator>
    <engineeringUnits/>
    <dataSourceXid>DS_000001</dataSourceXid>
    <deviceName>test1</deviceName>
    <name>line_load_percent01</name>
</dataPoints>

<dataPoints>
<xid>DP_000003</xid>
    <pointLocator>
        <range>HOLDING_REGISTER</range>
        <modbusDataType>FOUR_BYTE_FLOAT</modbusDataType>
        <offset>2852</offset>
    </pointLocator>
<engineeringUnits/>
<dataSourceXid>DS_000002</dataSourceXid>
<deviceName>test2</deviceName>
<name>line_load_percent02</name>
</dataPoints>

Python:

with open("test1.xml", 'r') as xml_file:

    obj = xmltodict.parse(xml_file.read())
    xml_file.close()

json_data = json.dumps(obj, indent=4)

with open("data.json", "w") as json_file:
    json_file.write(json_data)
    json_file.close()

OUPUT I want:

{
        "dataSources": [
            {
                "xid": "DS_000001",
                "type": "MODBUS_IP",
                "transportType": "TCP",
                "updatePeriodType": "MILLISECONDS",
                "host": "123.456.78.11",
                "name": "test1",
                "port": 502,
                "updatePeriods": 500
            },
            {
                "xid": "DS_000002",
                "type": "MODBUS_IP",
                "transportType": "TCP",
                "updatePeriodType": "MILLISECONDS",
                "host": "123.456.78.12",
                "name": "test2",
                "port": 502,
                "updatePeriods": 500
            }
        ],
        "dataPoints": [
            {
                "xid": "DP_00001",
                "pointLocator": {
                    "range": "HOLDING_REGISTER",
                    "modbusDataType": "FOUR_BYTE_FLOAT",
                    "offset": 2848
                },
                "engineeringUnits": null,
                "dataSourceXid": "DS_000001",
                "deviceName": "test1",
                "name": "line_load_percent00"
            },
            {
                "xid": "DP_00002",
                "pointLocator": {
                    "range": "HOLDING_REGISTER",
                    "modbusDataType": "FOUR_BYTE_FLOAT",
                    "offset": 2850
                },
                "engineeringUnits": null,
                "dataSourceXid": "DS_000001",
                "deviceName": "test1",
                "name": "line_load_percent01"
            },
            {
                    "xid": "DP_00003",
                    "pointLocator": {
                        "range": "HOLDING_REGISTER",
                        "modbusDataType": "FOUR_BYTE_FLOAT",
                        "offset": 2852
                    },
                    "engineeringUnits": null,
                    "dataSourceXid": "DS_000002",
                    "deviceName": "test2",
                    "name": "line_load_percent02"
                }
        ]
}

For the numbers only data like in offset,port etc. , how do I maintain it as an integer in JSON rather than a string value?

Thank You

1 Answers1

1

Wrapped the xml with a temporary root and then got rid of it at the end.

Also, got the _decode code from How to convert string int JSON into real int with json.loads

import json
import xmltodict

### this function code is from the link
def _decode(o):
    if isinstance(o, str) and o.isdigit():  # slight twist from original code for checking int
            return int(o)
    elif isinstance(o, dict):
        return {k: _decode(v) for k, v in o.items()}
    elif isinstance(o, list):
        return [_decode(v) for v in o]
    else:
        return o

with open("test1.xml", 'r') as xml_file:

    xml_string = xml_file.read()
    xml_string = "<root>" + xml_string + "</root>"  # wrap with temp <root>
    obj = xmltodict.parse(xml_string)
    xml_file.close()

json_string = json.dumps(xmltodict.parse(xml_string), indent=4)
json_data = json.loads(json_string, object_hook=_decode)["root"]  # <root> out

with open("data.json", 'w') as json_file:
    json.dump(json_data, json_file)
    json_file.close()

Joonyoung Park
  • 474
  • 3
  • 6