6

I am using dicttoxml in python for converting dict to XML .

I need to convert the dict to XML attributes.

For example:

dict

[
      {
           "@name":"Ravi",
           "@age":21,
           "college":"Anna University"
       }
]

Output XML

<Student name="Ravi" age=21>
  <college>Anna University</college>
</Student>

code

dicttoxml(dict, custom_root='Student', attr_type=False, root=True)

Actual Output

<Student>
  <key name="name">Ravi</key>
  <key name="age">21</key>
  <college>Anna University</college>
</Student>
jan-seins
  • 1,027
  • 14
  • 27
devanathan
  • 603
  • 2
  • 8
  • 34

5 Answers5

5

I might suggest declxml (full disclosure: I wrote it). With declxml, you create an object called a processor which declaratively defines the structure of your XML. You can use the processor to both parse and serialize XML data. declxml works with serializing to and from dictionaries, objects, and namedtuples. It handles attributes and arrays of elements and performs basic validation.

import declxml as xml


student = {
    'name':'Ravi',
    'age':21,
    'college':'Anna University'
}

student_processor = xml.dictionary('Student', [
    xml.string('.', attribute='name'),
    xml.integer('.', attribute='age'),
    xml.string('college')
])

xml.serialize_to_string(student_processor, student, indent='    ')

Which produces the desired output

<?xml version="1.0" ?>
<Student age="21" name="Ravi">
    <college>Anna University</college>
</Student>
gatkin
  • 521
  • 5
  • 5
4

I had a similar requirement to convert XML to dict and vice versa. I used a library called xmltodict. This lib allows you to reverse from dict to xml with attributes.

dict

xmldata = [
  {
       "@name":"Ravi",
       "@age":21,
       "college":"Anna University"
   }

]

code

import xmltodict

print(xmltodict.unparse(xmldata), pretty=True)
Hisham Haniffa
  • 309
  • 3
  • 6
3

This is not supported by dicttoxml as of yet, though the issue has been open from a long time. https://github.com/quandyfactory/dicttoxml/issues/27

Though if your needs are not that complex, you can try this simple serializer out.

https://gist.github.com/reimund/5435343/

found it here :- Serialize Python dictionary to XML

Community
  • 1
  • 1
1

I am also using xmltodict, I think there was a syntax error in Hisham's answer but I couldn't comment, so here it is :

import xmltodict

xmldata = {
       'Student': {
           '@name':'Ravi',
           '@age':21,
           "college":"Anna University"
           }
   }

print(xmltodict.unparse(xmldata,pretty=True))

output

<?xml version="1.0" encoding="utf-8"?>
<Student name="Ravi" age="21">
        <college>Anna University</college>
</Student>
devanathan
  • 603
  • 2
  • 8
  • 34
Angia
  • 47
  • 3
0

Here is some relatively simple code that makes decisions based on object types. If an object is a dictionary, its keys whose values are ones that would historically be considered "primitives" in a language like C or Java are written out as attributes, otherwise a sub-element is created. If an object is a list, an li element is created for each list item. Items which are primitives are written out as element text, but items which are dictionaries are written out as attributes.

#! python3-64

from lxml import etree

import json
import typing

def json_obj_to_xml(parent_element: typing.Optional[etree.Element], new_element_name: str, obj: typing.Union[bool, float, int, str, dict, list]):
    """
    Recursively walk an object and return its XML representation.

    Args:
        parent_element (typing.Optional[etree.Element]): The element that will be the parent of the element that this
            function will create and return.

        new_element_name (str): The name of the element that will be created.

        obj (typing.Union[bool, float, int, str, dict, list]): The object to return XML for.  It is expected that all
            objects passed to this function can be represented in JSON.

    Returns:
        result (etree.Element): An XML element.

    """

    if parent_element is not None:
        new_element = etree.SubElement(parent_element, new_element_name)

    else:
        new_element = etree.Element(new_element_name)

    if type(obj) == dict:
        for key, value in obj.items():
            if type(value) in (dict, list):
                json_obj_to_xml(new_element, key, value)

            else:
                # Convert values to a string, make sure boolean values are lowercase
                new_element.attrib[key] = str(value).lower() if type(value) == bool else str(value)

    elif type(obj) == list:
        for list_item in obj:
            # List items have to have a name.  Here we borrow "li" from HTML which stands for list item.
            json_obj_to_xml(new_element, 'li', list_item)

    else:
        # Convert everything to a string, make sure boolean values are lowercase
        new_element.text = str(obj).lower() if type(obj) == bool else str(obj)

    return new_element

# Read JSON file into a dictionary
json_file = r'C:\Users\ubiquibacon\Desktop\some_json_file.json'
json_file_hndl = open(json_file)
json_dict = json.load(json_file_hndl)
json_file_hndl.close()

# Recursively walk the dictionary to create the XML
root_xml_element = json_obj_to_xml(None, 'root', json_dict)

# Write the XML file
xml_file = f'{json_file}.xml'
with open(xml_file, 'wb') as xml_file_hndl:
    xml_file_hndl.write(etree.tostring(root_xml_element, pretty_print=True, xml_declaration=True))
ubiquibacon
  • 9,834
  • 25
  • 101
  • 175