Skip to content

Commit d085a68

Browse files
committed
added functionality to correctly parse xml lists
1 parent 0612b65 commit d085a68

File tree

4 files changed

+62
-7
lines changed

4 files changed

+62
-7
lines changed

requirements-test.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Django>=1.6
22
djangorestframework>=2.4.3
3-
pytest-django==2.6
3+
pytest-django==2.9.1
44
pytest==2.5.2
55
pytest-cov==1.6
66
flake8==2.2.2

rest_framework_xml/parsers.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ def parse(self, stream, media_type=None, parser_context=None):
3737

3838
return data
3939

40+
def _check_xml_list(self, element):
41+
"""
42+
Checks that an element has multiple tags and that they are all the same,
43+
to validate that the element is a properly formatted list
44+
"""
45+
return len(element) > 1 and len(set([child.tag for child in element])) <= 1
46+
4047
def _xml_convert(self, element):
4148
"""
4249
convert the xml `element` into the corresponding python object
@@ -48,7 +55,7 @@ def _xml_convert(self, element):
4855
return self._type_convert(element.text)
4956
else:
5057
# if the fist child tag is list-item means all children are list-item
51-
if children[0].tag == "list-item":
58+
if self._check_xml_list(element):
5259
data = []
5360
for child in children:
5461
data.append(self._xml_convert(child))

tests/test_parsers.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55

66
from django.test import TestCase
7-
from django.utils import unittest
87
from django.utils.six.moves import StringIO
98
from rest_framework_xml.parsers import XMLParser
109
from rest_framework_xml.compat import etree
@@ -52,15 +51,66 @@ def setUp(self):
5251
}
5352
]
5453
}
54+
self._invalid_list_input = StringIO(
55+
'<?xml version="1.0" encoding="utf-8"?>'
56+
'<root>'
57+
'<list>'
58+
'<list-item><sub_id>1</sub_id><sub_name>first</sub_name></list-item>'
59+
'<list-item2><sub_id>2</sub_id><sub_name>second</sub_name></list-item2>'
60+
'<list-item2><sub_id>3</sub_id><sub_name>third</sub_name></list-item2>'
61+
'</list>'
62+
'</root>'
63+
)
64+
self._invalid_list_output = {
65+
"list": {
66+
"list-item": {
67+
"sub_id": 1,
68+
"sub_name": "first"
69+
},
70+
"list-item2": {
71+
"sub_id": 3,
72+
"sub_name": "third"
73+
}
74+
}
75+
}
76+
self._valid_list_input = StringIO(
77+
'<?xml version="1.0" encoding="utf-8"?>'
78+
'<root>'
79+
'<list>'
80+
'<list-item><sub_id>1</sub_id><sub_name>first</sub_name></list-item>'
81+
'<list-item><sub_id>2</sub_id><sub_name>second</sub_name></list-item>'
82+
'</list>'
83+
'</root>'
84+
)
85+
self._valid_list_output = {
86+
"list": [
87+
{
88+
"sub_id": 1,
89+
"sub_name": "first"
90+
},
91+
{
92+
"sub_id": 2,
93+
"sub_name": "second"
94+
}
95+
]
96+
}
5597

56-
@unittest.skipUnless(etree, 'defusedxml not installed')
5798
def test_parse(self):
5899
parser = XMLParser()
59100
data = parser.parse(self._input)
60101
self.assertEqual(data, self._data)
61102

62-
@unittest.skipUnless(etree, 'defusedxml not installed')
63103
def test_complex_data_parse(self):
64104
parser = XMLParser()
65105
data = parser.parse(self._complex_data_input)
66106
self.assertEqual(data, self._complex_data)
107+
108+
def test_invalid_list_parse(self):
109+
parser = XMLParser()
110+
data = parser.parse(self._invalid_list_input)
111+
self.assertEqual(data, self._invalid_list_output)
112+
113+
def test_valid_list_parse(self):
114+
parser = XMLParser()
115+
data = parser.parse(self._valid_list_input)
116+
self.assertEqual(data, self._valid_list_output)

tests/test_renderers.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from decimal import Decimal
66

77
from django.test import TestCase
8-
from django.utils import unittest
98
from django.utils.six.moves import StringIO
109
from rest_framework_xml.renderers import XMLRenderer
1110
from rest_framework_xml.parsers import XMLParser
@@ -97,7 +96,6 @@ def test_render_list(self):
9796
self.assertXMLContains(content, '<sub_data_list><list-item>')
9897
self.assertXMLContains(content, '</list-item></sub_data_list>')
9998

100-
@unittest.skipUnless(etree, 'defusedxml not installed')
10199
def test_render_and_parse_complex_data(self):
102100
"""
103101
Test XML rendering.

0 commit comments

Comments
 (0)