diff options
| author | Cerberus <matt.dietz@rackspace.com> | 2010-09-28 13:09:25 -0500 |
|---|---|---|
| committer | Cerberus <matt.dietz@rackspace.com> | 2010-09-28 13:09:25 -0500 |
| commit | 41e8f72334bd7a69d86575c6fc855146e12dce59 (patch) | |
| tree | ad251208e23765deb21ba83227437b033fb29a75 /nova | |
| parent | 663ed27a2d7b3cb3a5290e0516eb8d602d7e65ba (diff) | |
| parent | fd41a784ccee500ae8a36311ad3c80963e866b31 (diff) | |
merge from gundlach
Diffstat (limited to 'nova')
| -rw-r--r-- | nova/tests/api/wsgi_test.py | 24 | ||||
| -rw-r--r-- | nova/wsgi.py | 51 |
2 files changed, 69 insertions, 6 deletions
diff --git a/nova/tests/api/wsgi_test.py b/nova/tests/api/wsgi_test.py index 145b1bfee..9425b01d0 100644 --- a/nova/tests/api/wsgi_test.py +++ b/nova/tests/api/wsgi_test.py @@ -121,3 +121,27 @@ class SerializerTest(unittest.TestCase): def test_suffix_takes_precedence_over_accept_header(self): self.match('/servers/4.xml', 'application/json', expect='xml') self.match('/servers/4.xml.', 'application/json', expect='json') + + def test_deserialize(self): + xml = """ + <a a1="1" a2="2"> + <bs><b>1</b><b>2</b><b>3</b><b><c c1="1"/></b></bs> + <d><e>1</e></d> + <f>1</f> + </a> + """.strip() + as_dict = dict(a={ + 'a1': '1', + 'a2': '2', + 'bs': ['1', '2', '3', {'c': dict(c1='1')}], + 'd': {'e': '1'}, + 'f': '1'}) + metadata = {'application/xml': dict(plurals={'bs': 'b', 'ts': 't'})} + serializer = wsgi.Serializer({}, metadata) + self.assertEqual(serializer.deserialize(xml), as_dict) + + def test_deserialize_empty_xml(self): + xml = """<a></a>""" + as_dict = {"a": {}} + serializer = wsgi.Serializer({}) + self.assertEqual(serializer.deserialize(xml), as_dict) diff --git a/nova/wsgi.py b/nova/wsgi.py index ac319db40..da9374542 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -21,8 +21,10 @@ Utility methods for working with WSGI servers """ +import json import logging import sys +from xml.dom import minidom import eventlet import eventlet.wsgi @@ -231,7 +233,7 @@ class Controller(object): class Serializer(object): """ - Serializes a dictionary to a Content Type specified by a WSGI environment. + Serializes and deserializes dictionaries to certain MIME types. """ def __init__(self, environ, metadata=None): @@ -256,21 +258,58 @@ class Serializer(object): def to_content_type(self, data): """ - Serialize a dictionary into a string. The format of the string - will be decided based on the Content Type requested in self.environ: - by Accept: header, or by URL suffix. + Serialize a dictionary into a string. + + The format of the string will be decided based on the Content Type + requested in self.environ: by Accept: header, or by URL suffix. """ return self.handler(data) + def deserialize(self, datastring): + """ + Deserialize a string to a dictionary. + + The string must be in the format of a supported MIME type. + """ + datastring = datastring.strip() + is_xml = (datastring[0] == '<') + if not is_xml: + return json.loads(datastring) + return self._from_xml(datastring) + + def _from_xml(self, datastring): + xmldata = self.metadata.get('application/xml', {}) + plurals = set(xmldata.get('plurals', {})) + node = minidom.parseString(datastring).childNodes[0] + return {node.nodeName: self._from_xml_node(node, plurals)} + + def _from_xml_node(self, node, listnames): + """ + Convert a minidom node to a simple Python type. + + listnames is a collection of names of XML nodes whose subnodes should + be considered list items. + """ + if len(node.childNodes) == 1 and node.childNodes[0].nodeType == 3: + return node.childNodes[0].nodeValue + elif node.nodeName in listnames: + return [self._from_xml_node(n, listnames) for n in node.childNodes] + else: + result = dict() + for attr in node.attributes.keys(): + result[attr] = node.attributes[attr].nodeValue + for child in node.childNodes: + if child.nodeType != node.TEXT_NODE: + result[child.nodeName] = self._from_xml_node(child, listnames) + return result + def _to_json(self, data): - import json return json.dumps(data) def _to_xml(self, data): metadata = self.metadata.get('application/xml', {}) # We expect data to contain a single key which is the XML root. root_key = data.keys()[0] - from xml.dom import minidom doc = minidom.Document() node = self._to_xml_node(doc, metadata, root_key, data[root_key]) return node.toprettyxml(indent=' ') |
