summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Gundlach <michael.gundlach@rackspace.com>2010-09-28 12:54:17 -0400
committerMichael Gundlach <michael.gundlach@rackspace.com>2010-09-28 12:54:17 -0400
commitfd41a784ccee500ae8a36311ad3c80963e866b31 (patch)
tree1d231f945e69223d5d98b7c9da608204deefa226
parent70516be4ff02cd82dce82ac1950fc55e87bab9ec (diff)
Add Serializer.deserialize(xml_or_json_string)
-rw-r--r--nova/tests/api/wsgi_test.py24
-rw-r--r--nova/wsgi.py51
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=' ')