Shashank Malali
Shashank Malali

Reputation: 13

Python script to convert an xml to json but with the arrays keeping as arrays and objects as objects

My Python scripts converts the xml to json. But the array of an for e.g address is converted to an object which I don't want. I want it to remain as array only. Below is my python script along with input xml and output json I am expecting. Thanks and appreciate your help In our application we take xml as an input string in a variable and also output json in a variable and test and compare the xml with the json

import json
import xmltodict

xml = xmltodict.parse(inputxml)
CustomerCreateandUpdate = xml['SyncCustomerCreateandUpdate']['DataArea']['CustomerCreateandUpdate']
outputjson = json.dumps(CustomerCreateandUpdate)

<?xml version="1.0" encoding="UTF-8"?>
<SyncCustomerCreateandUpdate xmlns="http://schema.infor.com/InforOAGIS/2" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" languageCode="EN" releaseID="9.2" 
systemEnvironmentCode="Production" versionID="2.11.0">
<ApplicationArea>
    <Sender>
        <LogicalID schemeVersionID="16.0.0.015">lid://infor.m3.m3</LogicalID>
        <ComponentID schemeVersionID="16.0.0.20201209170022">M3BE</ComponentID>
        <ConfirmationCode>OnError</ConfirmationCode>
    </Sender>
    <CreationDateTime>2021-03-04T12:33:12.487Z</CreationDateTime>
    <BODID>1bb40f80-8039-4264-b903-fa58ca2d3a9a</BODID>
</ApplicationArea>
<DataArea>
    <Sync>
        <AccountingEntityID>001_090</AccountingEntityID>
        <ActionCriteria>
            <ActionExpression actionCode="Add"/>
        </ActionCriteria>
    </Sync>
    <CustomerCreateandUpdate>
        <customerName>TEST1838</customerName>
        <customerStatus>Test5</customerStatus>
        <addresses>
            <addressLine1>test</addressLine1>
            <addressLine2>test</addressLine2>
            <addressLine3>test</addressLine3>
            <addressLine4>test</addressLine4>
            <postalCode>2200</postalCode>
            <city>Herentals</city>
            <stateCode>test</stateCode>
            <countryCode>BE</countryCode>
        </addresses>
        <phones>
            <phoneNumber>test</phoneNumber>
        </phones>
        <faxNumber>999</faxNumber>
        <contacts>
            <firstName>test</firstName>
            <lastName>test</lastName>
            <emailAddress>test</emailAddress>
            <mobilePhone>test</mobilePhone>
        </contacts>
        <emails>
            <emailType>TEST</emailType>
            <emailAddress>Test</emailAddress>
        </emails>
        <references>test</references>
        <freeFields>
            <number>0</number>
            <content>test</content>
        </freeFields>
        <searchKey>test</searchKey>
        <customerType>test</customerType>
        <description>test</description>
        <serviceArea>test</serviceArea>
        <lelyCenter>test</lelyCenter>
        <lspId>test</lspId>
        <m3Id>test</m3Id>
        <createdById>test</createdById>
        <lastModifiedById>test</lastModifiedById>
        <lastModifiedDate>test</lastModifiedDate>
        <vatNumber>test</vatNumber>
    </CustomerCreateandUpdate>
</DataArea>
Json expected output:

{
"customerName": "",
"customerStatus": "",
"addresses": [
{
  "addressLine1": "",
  "addressLine2": "",
  "addressLine3": "",
  "addressLine4": "",
  "postalCode": "",
  "city": "",
  "stateCode": "",
  "countryCode": ""
  }
   ],
  "phones": [
  {
  "phoneNumber": ""
  }
  ],
  "faxNumber": "",
 "contacts": [
  {
  "firstName": "",
  "lastName": "",
  "emailAddress": "",
  "mobilePhone": ""
   }
   ],
  "emails": [
   {
   "emailType": "",
   "emailAddress": ""
   }
   ],
  "references": [
  ""
  ],
  "freeFields": [
  {
  "number": 0,
  "content": ""
  }
   ],
 "language": "",
 "searchKey": "",
 "customerType": 0,
 "description": "",
 "lelyCenter": "",
 "lspId": "",
 "m3Id": "",
 "createdById": "",
 "lastModifiedById": "",
 "lastModifiedDate": "",
 "vatNumber": ""
 }

Upvotes: 0

Views: 623

Answers (1)

Martin Tovmassian
Martin Tovmassian

Reputation: 1468

The way address data is described in your xml drives xmltodict to represent it as a json object. First, address data sould be encapsulated into a dedicated container like so (How to represent list data in XML):

  <addresses>

    <address>
      <addressLine1>test</addressLine1>
      <addressLine2>test</addressLine2>
      <addressLine3>test</addressLine3>
      <addressLine4>test</addressLine4>
      <postalCode>2200</postalCode>
      <city>Herentals</city>
      <stateCode>test</stateCode>
      <countryCode>BE</countryCode>
    </address>

  </addresses>

But obviously this structure is not enough for xmltodict to detect it as a list of items. It needs to browse at least to times the same tag to understand it as an iterable. So if your address list has only one element you have to put a void address tag:

  <addresses>

    <address>
      <addressLine1>test</addressLine1>
      <addressLine2>test</addressLine2>
      <addressLine3>test</addressLine3>
      <addressLine4>test</addressLine4>
      <postalCode>2200</postalCode>
      <city>Herentals</city>
      <stateCode>test</stateCode>
      <countryCode>BE</countryCode>
    </address>

    <address></address>
    
  </addresses>

EDIT

With the new version of xmltodict it is not necessary to add a void tag. Just use the argument force_list={<tag name>} in the parse method (xmltodict does not return a list for one element):

xmltodict.parse(xml_data, force_list={"addresses"})

Upvotes: 1

Related Questions