From: XueChendi Date: Mon, 12 Aug 2013 16:25:43 +0000 (+0800) Subject: Interprete scoped key as nested tags X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=70d1ec67c19b1e7639c8bf658cb40a65878875a1;p=openstack-build%2Fcinder-build.git Interprete scoped key as nested tags Current codes in xml_util.py does not support REST xml so well when one tagname contains delimiter, it fails to be interpreted. So this patch is to interprete one tagname like "1" as a nested tag like "1". Fix bug:1205983 Change-Id: Ia3e1f4d6b6a739898b51bf052a784fa36ab7695e --- diff --git a/cinder/api/xmlutil.py b/cinder/api/xmlutil.py index a6149222b..af95010a7 100644 --- a/cinder/api/xmlutil.py +++ b/cinder/api/xmlutil.py @@ -345,6 +345,18 @@ class TemplateElement(object): # Attribute has no value, so don't include it pass + def getAttrib(self, obj): + """Get attribute""" + tmpattrib = {} + #Now set up all the attributes... + for key, value in self.attrib.items(): + try: + tmpattrib[key] = value(obj) + except KeyError: + # Attribute has no value, so don't include it + pass + return tmpattrib + def _render(self, parent, datum, patches, nsmap): """Internal rendering. @@ -364,25 +376,61 @@ class TemplateElement(object): tagname = self.tag(datum) else: tagname = self.tag - elem = etree.Element(tagname, nsmap=nsmap) + + # If the datum is None + if datum is not None: + tmpattrib = self.getAttrib(datum) + else: + tmpattrib = {} + + tagnameList = tagname.split(':') + insertIndex = 0 + + #If parent is not none and has same tagname + if parent is not None: + for i in range(0, len(tagnameList)): + tmpInsertPos = parent.find(tagnameList[i]) + if tmpInsertPos is None: + break + elif not cmp(parent.attrib, tmpattrib) == 0: + break + parent = tmpInsertPos + insertIndex = i + 1 + + if insertIndex >= len(tagnameList): + insertIndex = insertIndex - 1 + + #Create root elem + elem = etree.Element(tagnameList[insertIndex], nsmap=nsmap) + rootelem = elem + subelem = elem + + #Create subelem + for i in range((insertIndex + 1), len(tagnameList)): + subelem = etree.SubElement(elem, tagnameList[i]) + elem = subelem # If we have a parent, append the node to the parent if parent is not None: - parent.append(elem) + #If we can merge this element, then insert + if insertIndex > 0: + parent.insert(len(list(parent)), rootelem) + else: + parent.append(rootelem) # If the datum is None, do nothing else if datum is None: - return elem + return rootelem # Apply this template element to the element - self.apply(elem, datum) + self.apply(subelem, datum) # Additionally, apply the patches for patch in patches: - patch.apply(elem, datum) + patch.apply(subelem, datum) # We have fully rendered the element; return it - return elem + return rootelem def render(self, parent, obj, patches=[], nsmap=None): """Render an object. diff --git a/cinder/tests/api/test_xmlutil.py b/cinder/tests/api/test_xmlutil.py index 4e145e741..c0bd45af5 100644 --- a/cinder/tests/api/test_xmlutil.py +++ b/cinder/tests/api/test_xmlutil.py @@ -627,6 +627,35 @@ class TemplateTest(test.TestCase): str(obj['test']['image']['id'])) self.assertEqual(result[idx].text, obj['test']['image']['name']) + def test_serialize_with_delimiter(self): + # Our test object to serialize + obj = {'test': {'scope0:key1': 'Value1', + 'scope0:scope1:key2': 'Value2', + 'scope0:scope1:scope2:key3': 'Value3' + }} + + # Set up our master template + root = xmlutil.TemplateElement('test', selector='test') + key1 = xmlutil.SubTemplateElement(root, 'scope0:key1', + selector='scope0:key1') + key1.text = xmlutil.Selector() + key2 = xmlutil.SubTemplateElement(root, 'scope0:scope1:key2', + selector='scope0:scope1:key2') + key2.text = xmlutil.Selector() + key3 = xmlutil.SubTemplateElement(root, 'scope0:scope1:scope2:key3', + selector='scope0:scope1:scope2:key3') + key3.text = xmlutil.Selector() + serializer = xmlutil.MasterTemplate(root, 1) + xml_list = [] + xml_list.append("") + xml_list.append("Value1") + xml_list.append("Value2Value3") + xml_list.append("") + expected_xml = ''.join(xml_list) + result = serializer.serialize(obj) + result = result.replace('\n', '').replace(' ', '') + self.assertEqual(result, expected_xml) + class MasterTemplateBuilder(xmlutil.TemplateBuilder): def construct(self):