]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Interprete scoped key as nested tags
authorXueChendi <chendi.xue@intel.com>
Mon, 12 Aug 2013 16:25:43 +0000 (00:25 +0800)
committerXueChendi <chendi.xue@intel.com>
Wed, 14 Aug 2013 02:02:10 +0000 (10:02 +0800)
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 "<a:b>1</a:b>" as a nested tag like
"<a><b>1</a></b>".

Fix bug:1205983

Change-Id: Ia3e1f4d6b6a739898b51bf052a784fa36ab7695e

cinder/api/xmlutil.py
cinder/tests/api/test_xmlutil.py

index a6149222b35fc0c14415df97e7f850973f5dcf83..af95010a7f8b399998c43062fff5000ab3608b02 100644 (file)
@@ -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.
index 4e145e741d9f87affbc2f9d5152b6e9d5079fc0d..c0bd45af59a226b23b0ca77c85dbfe250ff4d1ce 100644 (file)
@@ -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("<?xmlversion='1.0'encoding='UTF-8'?><test>")
+        xml_list.append("<scope0><key1>Value1</key1><scope1>")
+        xml_list.append("<key2>Value2</key2><scope2><key3>Value3</key3>")
+        xml_list.append("</scope2></scope1></scope0></test>")
+        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):