jpadilla / django-rest-framework-xml

XML support for Django REST Framework

Home Page:http://jpadilla.github.io/django-rest-framework-xml

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

XMLRenderer when passed a list of items

AronForero opened this issue · comments

When I pass a Python Dict like this to the renderer:

from rest_framework_xml.renderers import XMLRenderer

dictionary = {
    'NAME': 'Aron Dev',
    'ID': 555000777,
    'PHONE_NUMBER': [
        3124569874,
        3021452361,
    ]
}

renderer = XMLRenderer()
new_data = renderer.render(dictionary)

The library will return the following XML struct:

<NAME>Aron Dev</NAME>
<ID>555000777</ID>  
<PHONE_NUMBER>
    <list-item>3124569874</list-item>
    <list-item>3124569874</list-item>
<PHONE_NUMBER>  

But I needed two 'PHONE_NUMBER' tags (that tag 'list-item' is not really useful), one for each value of the list, just like this:

<PHONE_NUMBER>3124569874<PHONE_NUMBER>
<PHONE_NUMBER>3124569874<PHONE_NUMBER>

I FOUND THIS WALKAROUND

Create a new custom class that inherits from the XMLRenderer class as follows (the lines between the arrows are the new ones I've added):

class CustomXmlRenderer(XMLRenderer):
    item_tag_name = 'PHONE_NUMBER'
    
    def _to_xml(self, xml, data):
        ...
        elif isinstance(data, dict):
            for key, value in six.iteritems(data):
            --->if isinstance(value, list):<---
                --->self._to_xml(xml, value)<---
                --->continue<---
                xml.startElement(key, {})
                self._to_xml(xml, value)
                xml.endElement(key)

I modified the first elif statement, adding a new condition that checks if the value is a List, to then create tags with the same name for each value of the List, and finally I added a continue to go on to the next item and avoid create more tags with the values of the list.

I Hope to help anyone who has got the same task that I had, and doesn't know what to do, or at least saven them some time

I don't know if it could be intagrated with the main project but I'll be watching :)

Hello and thanks for posting this. Had a similar issue where I was serializing a nested list in list of items. As the nested list has to have a different element to start with (item_tag_name), my modification looks as following.

        ...
        elif isinstance(data, dict):
            for key, value in data.items():
                if isinstance(value, list):
                    for v in value:
                        xml.startElement(key, {})
                        self._to_xml(xml, v)
                        xml.endElement(key)
                else:
                    xml.startElement(key, {})
                    self._to_xml(xml, value)
                    xml.endElement(key)