[Commits] (grant) Re-fix Bug 1013 (Nested XML syntax alternative) r=alecf

commits at osafoundation.org commits at osafoundation.org
Tue Mar 1 17:48:37 PST 2005


Commit by: grant
Modified files:
chandler/application/Parcel.py 1.51 1.52
chandler/application/tests/TestAnonymous.py 1.2 1.3
chandler/application/tests/testparcels/anonymous/parcel.xml 1.4 1.5

Log message:
Re-fix Bug 1013 (Nested XML syntax alternative) r=alecf

- Change Parcel.py to create attribute values that are Items at
  the start of parsing their elements' XML tags. This way, if these
  items have sub-attributes, the loader can correctly identify which
  items the sub-attributes are referring to.

- In the Parcel.ValueSet class, when creating relative paths for anonymous
  items, make sure we don't use "None" for path components.

- Update the unit tests to include a case for parsing sub-attributes of
  anonymous items that are themselves values of attributes.



ViewCVS links:
http://cvs.osafoundation.org/index.cgi/chandler/application/Parcel.py.diff?r1=text&tr1=1.51&r2=text&tr2=1.52
http://cvs.osafoundation.org/index.cgi/chandler/application/tests/TestAnonymous.py.diff?r1=text&tr1=1.2&r2=text&tr2=1.3
http://cvs.osafoundation.org/index.cgi/chandler/application/tests/testparcels/anonymous/parcel.xml.diff?r1=text&tr1=1.4&r2=text&tr2=1.5

Index: chandler/application/tests/testparcels/anonymous/parcel.xml
diff -u chandler/application/tests/testparcels/anonymous/parcel.xml:1.4 chandler/application/tests/testparcels/anonymous/parcel.xml:1.5
--- chandler/application/tests/testparcels/anonymous/parcel.xml:1.4	Thu Feb 24 17:02:36 2005
+++ chandler/application/tests/testparcels/anonymous/parcel.xml	Tue Mar  1 17:48:35 2005
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<!-- $Revision: 1.4 $ -->
-<!-- $Date: 2005/02/25 01:02:36 $ -->
+<!-- $Revision: 1.5 $ -->
+<!-- $Date: 2005/03/02 01:48:35 $ -->
 <!-- Copyright (c) 2003-2004 Open Source Applications Foundation -->
 <!-- License: http://osafoundation.org/Chandler_0.1_license_terms.htm -->
 
@@ -28,19 +28,21 @@
       </Attribute>
   </Kind>
   
+  <this:myKind itsName="itemWithSubItem">
+    <this:myKind />
+    <this:myKind />
+  </this:myKind>
+
   <this:myKind itsName="itemWithAttributes">
       <this:myAttribute key="one"/>
       <this:myAttribute key="two"/>
       <this:myAttribute key="three"/>
   </this:myKind>
   
-  <this:myKind itsName="itemWithSubItem">
-    <this:myInner>
-        <!-- eventually we should be able to uncomment this to set
-             attributes on inner anonymous nodes -->
-        <!-- <innerAttr value="Inner attribute value"/> -->
-    </this:myInner>
-    <this:myKind />
+  <this:myKind itsName="anonymousItemWithAttributes">
+      <this:myInnerKind>
+          <innerAttr value="Inner attribute value" />
+      </this:myInnerKind>
   </this:myKind>
 
 </Parcel>

Index: chandler/application/tests/TestAnonymous.py
diff -u chandler/application/tests/TestAnonymous.py:1.2 chandler/application/tests/TestAnonymous.py:1.3
--- chandler/application/tests/TestAnonymous.py:1.2	Thu Feb 24 17:02:36 2005
+++ chandler/application/tests/TestAnonymous.py	Tue Mar  1 17:48:34 2005
@@ -1,8 +1,8 @@
 """
 Anonymous item tests for Parcel Loader
 """
-__revision__  = "$Revision: 1.2 $"
-__date__      = "$Date: 2005/02/25 01:02:36 $"
+__revision__  = "$Revision: 1.3 $"
+__date__      = "$Date: 2005/03/02 01:48:34 $"
 __copyright__ = "Copyright (c) 2003-2004 Open Source Applications Foundation"
 __license__   = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
 
@@ -72,12 +72,42 @@
         self.assert_(attributeValue)
         
         for key, value in attributeValue.iteritems():
+            # Raise if any of the children has a name
+            self.assert_(value.itsName == None)
             # Raise if value is not present in itemChildren 
             index = itemChildren.index(value)
             del itemChildren[index]
             
         self.assert_(itemChildren == [])
 
+    def testAnonymousItemWithAttributes(self):
+        """
+        Test to ensure anonymous items (i.e. items without an itsName
+        parameter in parcel.xml) can be set up correctly when they are
+        specified as values of an attribute.
+        """
+
+        item = self.manager.lookup("http://testparcels.org/anonymous",
+                                   "anonymousItemWithAttributes")
+
+        #PrintItem("//parcels/anonymous", self.manager.repo, recursive=True)
+        
+        self.assert_(item)
+
+        itemChildren = [child for child in item.iterChildren()]
+        
+        self.assert_(itemChildren)
+        self.assert_(len(itemChildren) == 1)
+
+        anonymousChild = itemChildren[0]
+        
+        self.assert_(anonymousChild)
+        self.assert_(anonymousChild.itsName == None)
+
+        attributeValue = anonymousChild.innerAttr
+        self.assert_(attributeValue == "Inner attribute value")
+
+
 
 if __name__ == "__main__":
     unittest.main()

Index: chandler/application/Parcel.py
diff -u chandler/application/Parcel.py:1.51 chandler/application/Parcel.py:1.52
--- chandler/application/Parcel.py:1.51	Fri Feb 25 10:15:54 2005
+++ chandler/application/Parcel.py	Tue Mar  1 17:48:34 2005
@@ -978,7 +978,6 @@
                 if element is not 'Ignore':
                     currentItem = self.createItem(kind, parent,
                                                   nameString, classString)
-                    self.itemsCreated.append(currentItem)
 
         elif nameString:
             
@@ -1047,7 +1046,18 @@
 
             if attrs.has_key((None, 'value')):
                 currentValue = attrs.getValue((None, 'value'))
-    
+            else:
+                item = self.__getCurrentItem()
+                
+                if item is not None:
+                    itemType = self._getTypeForAttribute(item, uri, local, attrs)
+                    
+                    if itemType is not None and \
+                       itemType.itsKind.itsUUID == self.manager.kindUUID:
+                        currentItem = self.createItem(itemType, item,
+                                                      None, None)
+                        currentValue = currentItem
+
         # Add the tag to our context stack
         self.elementStack.append(ParcelXMLElement(uri, local, attrs,
                           element, currentItem,
@@ -1055,6 +1065,80 @@
                           self.currentAssignments,
                           self.reloadingCurrentItem))
 
+    def _getTypeForAttribute(self, currentItem,
+                             elementUri, elementLocal, elementAttrs):
+        resultType = None
+        
+        if elementAttrs.has_key((None, 'type')):
+            # Store the full path to the type item
+            (typeNamespace, typeName) = \
+             self.getNamespaceName(elementAttrs.getValue((None, 'type')))
+            resultType = self.manager.lookup(typeNamespace, typeName)
+            if resultType is None:
+                explanation = \
+                 "Type doesn't exist: %s:%s" % (typeNamespace, typeName)
+                self.saveExplanation(explanation)
+                raise ParcelException(explanation)
+        
+        # "initialValue", regrettably, is a special case. In many cases, we
+        # don't know enough about its Kind to be able to figure out the correct
+        # type (eg, we need to know <type> and possibly <cardinality>), but
+        # due to the delayed assignment mechanism, these aren't known at the
+        # time this method is called.
+        #
+        # One way to fix this would be to parse "initialValue" when
+        # self.schemaPhase is False. (Or change Manager.handleKind() to
+        # be able to reject attributes as well as kinds).
+        if elementLocal != "initialValue":
+            
+            if resultType is None:
+                #
+                # Possibly element is pointing to an attribute
+                # of currentItem
+                #
+                if currentItem is None:
+                    explanation = "Neither attribute type or item specified"
+                    self.saveExplanation(explanation)
+                    raise ParcelException(explanation)
+
+                kindItem = currentItem.itsKind
+                try:
+                    resultType = kindItem.getAttribute(elementLocal)
+                except AttributeError:
+                    resultType = None
+
+            if resultType is None:
+                #
+                # See what the (elementUri, elementLocal) pair point to.
+                # Hopefully, it's either some known attribute of the
+                # currentItem, or a type (including kinds).
+                resultType = self.manager.lookup(elementUri, elementLocal)
+
+            if resultType is None:
+                explanation = \
+                            "Kind %s does not have the attribute '%s'" \
+                            % (kindItem.itsPath, elementLocal)
+                self.saveExplanation(explanation)
+                raise ParcelException(explanation)
+                
+
+            # If it's an Attribute, try to figure out the appropriate
+            # type
+            if resultType.itsKind.itsUUID == self.manager.attrUUID:
+                
+                try:
+                    resultType = resultType.type
+                except Exception, e:
+                    explanation = \
+                        "Unable to determine type of attribute '%s' for value '%s':'%s'" % \
+                        ( resultType.itsPath, currentElement.value, e )
+                    self.saveExplanation(explanation)
+                    raise
+                
+        return resultType
+
+
+
     def endElementNS(self, (uri, local), qname):
         """SAX2 callback for the end of a tag"""
 
@@ -1081,64 +1165,10 @@
                 self.currentAssignments = nextElement.assignments
                 self.reloadingCurrentItem = nextElement.reloading
         elif currentElement.elementType in ('Attribute', 'Subattribute'):
-            currentType = None
-            if currentElement.attributes.has_key((None, 'type')):
-                # Store the full path to the type item
-                (typeNamespace, typeName) = \
-                 self.getNamespaceName(currentElement.attributes.getValue((None, 'type')))
-                currentType = self.manager.lookup(typeNamespace, typeName)
-                if currentType is None:
-                    explanation = \
-                     "Type doesn't exist: %s:%s" % (typeNamespace, typeName)
-                    self.saveExplanation(explanation)
-                    raise ParcelException(explanation)
-            
-            if elementLocal != "initialValue":
-                
-                if currentType is None:
-                    #
-                    # Possibly element is pointing to an attribute
-                    # of currentItem
-                    #
-                    if currentItem is None:
-                        explanation = "Neither attribute type or item specified"
-                        self.saveExplanation(explanation)
-                        raise ParcelException(explanation)
-    
-                    kindItem = currentItem.itsKind
-                    try:
-                        currentType = kindItem.getAttribute(elementLocal)
-                    except AttributeError:
-                        currentType = None
-    
-                if currentType is None:
-                    #
-                    # See what the (elementUri, elementLocal) pair point to.
-                    # Hopefully, it's either some known attribute of the
-                    # currentItem, or a type (including kinds).
-                    currentType = self.manager.lookup(elementUri, elementLocal)
-    
-                if currentType is None:
-                    explanation = \
-                                "Kind %s does not have the attribute '%s'" \
-                                % (kindItem.itsPath, elementLocal)
-                    self.saveExplanation(explanation)
-                    raise ParcelException(explanation)
-                    
-
-                # If it's an Attribute, try to figure out the appropriate
-                # type
-                if currentType.itsKind.itsUUID == self.manager.attrUUID:
-                    
-                    try:
-                        currentType = currentType.type
-                    except Exception, e:
-                        explanation = \
-                            "Unable to determine type of attribute '%s' for value '%s':'%s'" % \
-                            ( currentType.itsPath, currentElement.value, e )
-                        self.saveExplanation(explanation)
-                        raise
-
+            currentType = self._getTypeForAttribute(currentItem,
+                                                    elementUri,
+                                                    elementLocal, 
+                                                    currentElement.attributes)
             # For non-top-level attributes (i.e. literals), make sure we
             # propagate the value up the tags stack.
             if (len(self.elementStack) >= 2):
@@ -1255,13 +1285,7 @@
 
         value = rawValue
         
-        # If we have a Kind, we should create a new Item that's
-        # an anonymous child of item.
-        if valueType.itsKind.itsUUID == self.manager.kindUUID:
-            
-            value = valueType.newItem(None, item)
-        
-        elif type(value) in (unicode, str):
+        if type(value) in (unicode, str):
             try:
                 value = valueType.makeValue(value)
             except Exception, e:
@@ -1359,6 +1383,8 @@
             self.saveExplanation(explanation)
             raise ParcelException(explanation)
 
+        self.itemsCreated.append(item)
+
         return item
 
     def completeAssignments(self, item, assignments):
@@ -1581,10 +1607,20 @@
             relPath = ""
             parcel = item
         else:
-            relPath = str(item.itsName)
+            #
+            # Note that it's possible (for anonymous items)
+            # to have an itsName of None. So, we don't want
+            # to build up the relative path to each item by using
+            # str(item.itsName), or item.itsName, because those
+            # return "None", or None. Instead, we use item.itsPath[-1]:
+            # that returns the UUID-generated path component the
+            # repository uses for anonymous items, and is suitable for
+            # tracking down items for comparisons.
+            #
+            relPath = item.itsPath[-1]
             parcel = item.itsParent
             while str(parcel.itsKind.itsPath) != "//Schema/Core/Parcel":
-                relPath = "%s/%s" % (str(parcel.itsName), relPath)
+                relPath = "%s/%s" % (parcel.itsPath[-1], relPath)
                 parcel = parcel.itsParent
 
         # parcel now points to a parcel



More information about the Commits mailing list