Fixes Invalid tag name error when using k:v tagname
This patch fixes the invalid tag name error when k:v type tagname appears in response of api during xml serialization, the tagname which contains colon couldn't be supported by default since it is reserved by xml namespace, this patch solve it by adding the k of k:v tagname into namespace. Fixes bug: #1213927 Change-Id: Ib20efb378425cbe5deef45fbac561955cbe0f7bc
This commit is contained in:
@@ -32,7 +32,8 @@ authorize = extensions.extension_authorizer('compute', 'flavorextraspecs')
|
||||
|
||||
class ExtraSpecsTemplate(xmlutil.TemplateBuilder):
|
||||
def construct(self):
|
||||
return xmlutil.MasterTemplate(xmlutil.make_flat_dict('extra_specs'), 1)
|
||||
extra_specs_dict = xmlutil.make_flat_dict('extra_specs', colon_ns=True)
|
||||
return xmlutil.MasterTemplate(extra_specs_dict, 1)
|
||||
|
||||
|
||||
class ExtraSpecTemplate(xmlutil.TemplateBuilder):
|
||||
|
||||
@@ -28,7 +28,8 @@ from nova.openstack.common.gettextutils import _
|
||||
|
||||
class ExtraSpecsTemplate(xmlutil.TemplateBuilder):
|
||||
def construct(self):
|
||||
return xmlutil.MasterTemplate(xmlutil.make_flat_dict('extra_specs'), 1)
|
||||
extra_specs_dict = xmlutil.make_flat_dict('extra_specs', colon_ns=True)
|
||||
return xmlutil.MasterTemplate(extra_specs_dict, 1)
|
||||
|
||||
|
||||
class ExtraSpecTemplate(xmlutil.TemplateBuilder):
|
||||
|
||||
@@ -141,7 +141,7 @@ class TemplateElement(object):
|
||||
"""Represent an element in the template."""
|
||||
|
||||
def __init__(self, tag, attrib=None, selector=None, subselector=None,
|
||||
**extra):
|
||||
colon_ns=False, **extra):
|
||||
"""Initialize an element.
|
||||
|
||||
Initializes an element in the template. Keyword arguments
|
||||
@@ -159,6 +159,9 @@ class TemplateElement(object):
|
||||
This is used to further refine the datum
|
||||
object returned by selector in the event
|
||||
that it is a list of objects.
|
||||
:colon_ns: An optional flag indicates whether support k:v
|
||||
type tagname, if so the k:v type tagname will
|
||||
be supported by adding the k into namespace.
|
||||
"""
|
||||
|
||||
# Convert selector into a Selector
|
||||
@@ -178,6 +181,7 @@ class TemplateElement(object):
|
||||
self._text = None
|
||||
self._children = []
|
||||
self._childmap = {}
|
||||
self.colon_ns = colon_ns
|
||||
|
||||
# Run the incoming attributes through set() so that they
|
||||
# become selectorized
|
||||
@@ -367,6 +371,15 @@ class TemplateElement(object):
|
||||
tagname = self.tag(datum)
|
||||
else:
|
||||
tagname = self.tag
|
||||
|
||||
if self.colon_ns:
|
||||
if ':' in tagname:
|
||||
if nsmap is None:
|
||||
nsmap = {}
|
||||
colon_key, colon_name = tagname.split(':')
|
||||
nsmap[colon_key] = colon_key
|
||||
tagname = '{%s}%s' % (colon_key, colon_name)
|
||||
|
||||
elem = etree.Element(tagname, nsmap=nsmap)
|
||||
|
||||
# If we have a parent, append the node to the parent
|
||||
@@ -496,7 +509,7 @@ class TemplateElement(object):
|
||||
|
||||
|
||||
def SubTemplateElement(parent, tag, attrib=None, selector=None,
|
||||
subselector=None, **extra):
|
||||
subselector=None, colon_ns=False, **extra):
|
||||
"""Create a template element as a child of another.
|
||||
|
||||
Corresponds to the etree.SubElement interface. Parameters are as
|
||||
@@ -509,7 +522,7 @@ def SubTemplateElement(parent, tag, attrib=None, selector=None,
|
||||
|
||||
# Get a TemplateElement
|
||||
elem = TemplateElement(tag, attrib=attrib, selector=selector,
|
||||
subselector=subselector)
|
||||
subselector=subselector, colon_ns=colon_ns)
|
||||
|
||||
# Append the parent safely
|
||||
if parent is not None:
|
||||
@@ -878,7 +891,8 @@ def make_links(parent, selector=None):
|
||||
return elem
|
||||
|
||||
|
||||
def make_flat_dict(name, selector=None, subselector=None, ns=None):
|
||||
def make_flat_dict(name, selector=None, subselector=None,
|
||||
ns=None, colon_ns=False):
|
||||
"""
|
||||
Utility for simple XML templates that traditionally used
|
||||
XMLDictSerializer with no metadata. Returns a template element
|
||||
@@ -902,10 +916,11 @@ def make_flat_dict(name, selector=None, subselector=None, ns=None):
|
||||
|
||||
# Build the root element
|
||||
root = TemplateElement(elemname, selector=selector,
|
||||
subselector=subselector)
|
||||
subselector=subselector, colon_ns=colon_ns)
|
||||
|
||||
# Build an element to represent all the keys and values
|
||||
elem = SubTemplateElement(root, tagname, selector=get_items)
|
||||
elem = SubTemplateElement(root, tagname, selector=get_items,
|
||||
colon_ns=colon_ns)
|
||||
elem.text = 1
|
||||
|
||||
# Return the template
|
||||
|
||||
@@ -217,3 +217,13 @@ class FlavorsExtraSpecsXMLSerializerTest(test.TestCase):
|
||||
'<extra_spec key="key1">value1</extra_spec>')
|
||||
text = serializer.serialize(dict({"key1": "value1"}))
|
||||
self.assertEqual(text, expected)
|
||||
|
||||
def test_serializer_with_colon_tagname(self):
|
||||
# Our test object to serialize
|
||||
obj = {'extra_specs': {'foo:bar': '999'}}
|
||||
serializer = flavorextraspecs.ExtraSpecsTemplate()
|
||||
expected_xml = (("<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
'<extra_specs><foo:bar xmlns:foo="foo">999</foo:bar>'
|
||||
'</extra_specs>'))
|
||||
result = serializer.serialize(obj)
|
||||
self.assertEqual(expected_xml, result)
|
||||
|
||||
@@ -214,3 +214,13 @@ class FlavorsExtraSpecsXMLSerializerTest(test.TestCase):
|
||||
'<extra_spec key="key1">value1</extra_spec>')
|
||||
text = serializer.serialize(dict({"key1": "value1"}))
|
||||
self.assertEqual(text, expected)
|
||||
|
||||
def test_serializer_with_colon_tagname(self):
|
||||
# Our test object to serialize
|
||||
obj = {'extra_specs': {'foo:bar': '999'}}
|
||||
serializer = flavors_extraspecs.ExtraSpecsTemplate()
|
||||
expected_xml = (("<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
'<extra_specs><foo:bar xmlns:foo="foo">999</foo:bar>'
|
||||
'</extra_specs>'))
|
||||
result = serializer.serialize(obj)
|
||||
self.assertEqual(expected_xml, result)
|
||||
|
||||
@@ -708,6 +708,22 @@ class TemplateTest(test.TestCase):
|
||||
templ = xmlutil.Template(None)
|
||||
self.assertEqual(templ.serialize(None), '')
|
||||
|
||||
def test_serialize_with_colon_tagname_support(self):
|
||||
# Our test object to serialize
|
||||
obj = {'extra_specs': {'foo:bar': '999'}}
|
||||
expected_xml = (("<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
'<extra_specs><foo:bar xmlns:foo="foo">999</foo:bar>'
|
||||
'</extra_specs>'))
|
||||
# Set up our master template
|
||||
root = xmlutil.TemplateElement('extra_specs', selector='extra_specs',
|
||||
colon_ns=True)
|
||||
value = xmlutil.SubTemplateElement(root, 'foo:bar', selector='foo:bar',
|
||||
colon_ns=True)
|
||||
value.text = xmlutil.Selector()
|
||||
master = xmlutil.MasterTemplate(root, 1)
|
||||
result = master.serialize(obj)
|
||||
self.assertEqual(expected_xml, result)
|
||||
|
||||
|
||||
class MasterTemplateBuilder(xmlutil.TemplateBuilder):
|
||||
def construct(self):
|
||||
@@ -800,6 +816,18 @@ class MiscellaneousXMLUtilTests(test.TestCase):
|
||||
result = tmpl.serialize(dict(wrapper=dict(a='foo', b='bar')))
|
||||
self.assertEqual(result, expected_xml)
|
||||
|
||||
def test_make_flat_dict_with_colon_tagname_support(self):
|
||||
# Our test object to serialize
|
||||
obj = {'extra_specs': {'foo:bar': '999'}}
|
||||
expected_xml = (("<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
'<extra_specs><foo:bar xmlns:foo="foo">999</foo:bar>'
|
||||
'</extra_specs>'))
|
||||
# Set up our master template
|
||||
root = xmlutil.make_flat_dict('extra_specs', colon_ns=True)
|
||||
master = xmlutil.MasterTemplate(root, 1)
|
||||
result = master.serialize(obj)
|
||||
self.assertEqual(expected_xml, result)
|
||||
|
||||
def test_safe_parse_xml(self):
|
||||
|
||||
normal_body = ('<?xml version="1.0" ?>'
|
||||
|
||||
Reference in New Issue
Block a user