commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnue] r8096 - in trunk/gnue-common/src: definitions logic


From: johannes
Subject: [gnue] r8096 - in trunk/gnue-common/src: definitions logic
Date: Tue, 15 Nov 2005 07:35:44 -0600 (CST)

Author: johannes
Date: 2005-11-15 07:35:43 -0600 (Tue, 15 Nov 2005)
New Revision: 8096

Modified:
   trunk/gnue-common/src/definitions/GBinary.py
   trunk/gnue-common/src/definitions/GObjects.py
   trunk/gnue-common/src/definitions/GParser.py
   trunk/gnue-common/src/definitions/GParserHelpers.py
   trunk/gnue-common/src/definitions/GRootObj.py
   trunk/gnue-common/src/definitions/__init__.py
   trunk/gnue-common/src/logic/GTrigger.py
Log:
Code cleanup according to technote 15 


Modified: trunk/gnue-common/src/definitions/GBinary.py
===================================================================
--- trunk/gnue-common/src/definitions/GBinary.py        2005-11-11 18:27:31 UTC 
(rev 8095)
+++ trunk/gnue-common/src/definitions/GBinary.py        2005-11-15 13:35:43 UTC 
(rev 8096)
@@ -1,130 +1,209 @@
+# GNU Enterprise Common Library - GNUe XML object definitions - Binary objects
 #
-# This file is part of GNU Enterprise.
+# Copyright 2001-2005 Free Software Foundation
 #
-# GNU Enterprise is free software; you can redistribute it 
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise is free software; you can redistribute it
 # and/or modify it under the terms of the GNU General Public
-# License as published by the Free Software Foundation; either 
+# License as published by the Free Software Foundation; either
 # version 2, or (at your option) any later version.
 #
 # GNU Enterprise is distributed in the hope that it will be
 # useful, but WITHOUT ANY WARRANTY; without even the implied
-# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 # PURPOSE. See the GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public 
+# You should have received a copy of the GNU General Public
 # License along with program; see the file COPYING. If not,
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# Copyright 2000-2005 Free Software Foundation
-#
-#
-# FILE:
-# GBinary.py
-#
-# DESCRIPTION:
-# Provides a container object for binary data. 
-#
-# NOTES:
-#
+# $Id$
 
+"""
+Provides a container object for binary data. 
+"""
 
+__all__ = ['UnsupportedFormatError', 'GBinary', 'getXMLelements']
+
 import base64
+
+from gnue.common.apps import errors
 from gnue.common.definitions.GObjects import GObj
 
-#
+
+# =============================================================================
+# Exceptions
+# =============================================================================
+
+class UnsupportedFormatError (errors.ApplicationError):
+  def __init__ (self, format):
+    msg = u_("Unsupported binary format: '%(format)s'") % {'format': format}
+    raise errors.ApplicationError.__init__ (self, msg)
+
+
+# =============================================================================
 # GBinary
-#
-#
-class GBinary(GObj):
-  def __init__(self, name="GBinary", parent=None):
-    GObj.__init__(self, name, parent=None)
-    self.__data__ = ""
-    self.format = "base64"
+# =============================================================================
+
+class GBinary (GObj):
+  """
+  Container class for binary data. The only format currently supported is
+  'base64'.
+  """
+
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__(self, name = "GBinary", parent = None):
+
+    GObj.__init__ (self, name, parent = None)
+    self.__data__    = ""
+    self.format      = "base64"
     self._phaseInits = [self.init]
 
-  def init(self):
 
+  # ---------------------------------------------------------------------------
+  # Initialize instance
+  # ---------------------------------------------------------------------------
+
+  def init (self):
+    """
+    Prepare the __data__ attribute from all the children's contents.
+
+    @raises UnsupportedFormatError: if the format is not supported
+    """
+
     if self.format == 'base64':
-      self.__data__ = base64.decodestring(self.getChildrenAsContent())
+      self.__data__ = base64.decodestring (self.getChildrenAsContent ())
     else:
-      raise "Unsupported binary format: %s" % self.format
+      raise UnsupportedFormatError, self.format
 
     self._children = []
 
-  def set(self, data):
+
+  # ---------------------------------------------------------------------------
+  # Set the data for the object
+  # ---------------------------------------------------------------------------
+
+  def set (self, data):
+    """
+    Set the data for the object
+
+    @param data: the data to set
+    """
+
     self.__data__ = data
 
-  def get(self, data):
+
+  # ---------------------------------------------------------------------------
+  # Get the currenlty defined data
+  # ---------------------------------------------------------------------------
+
+  def get (self, data):
+    """
+    @returns: the data of this object
+    """
+
     return data
 
-  #
-  # dumpXML
-  #
+
+  # ---------------------------------------------------------------------------
   # Dumps an XML representation of the object
-  # used in saving
-  #
-  def dumpXML(self, lookupDict, treeDump=None, gap=None,xmlnamespaces={},
-      stripPrefixes = None):
+  # ---------------------------------------------------------------------------
 
+  def _dumpXML_ (self, lookupDict, treeDump, gap, xmlnamespaces, textEncoding,
+      stripPrefixes, escape):
+    """
+    Return a XML representation of the object.
+
+    @param lookupDict: dictionary describing the XML entities, their
+      attributes and types
+    @param treeDump: if True, also include a XML representation of all 
children 
+    @param gap: string defining the current indentation level
+    @param xmlnamespaces: dictionary with the available XML namespaces
+    @param textEncoding: encoding used to transform string-type attributes into
+      unicode. If textEncoding is set to '<locale>' (default) it will be set to
+      the configuration variable 'textEncoding', i.e. from gnue.conf
+    @param stripPrefixes: a list of prefixes that will automatically be removed
+      from the objects type.  This can be used to remove the GF from the start
+      of all the gnue-forms objects.  If set to None (the default) then the
+      behaviour will be the old style which removes the first two characters
+      from the type.
+    @param escape: if set to True the resulting XML string should be escaped
+
+    @returns: a string with the object's XML representation
+    """
+
     xmlEntity = "binary"
-    xmlString = "%s<%s" % (gap[:-2],xmlEntity)
+    xmlString = "%s<%s" % (gap [:-2],xmlEntity)
 
-    indent = len(xmlString)
-    pos = indent
-    for attribute in self.__dict__.keys():
+    indent = len (xmlString)
+    pos    = indent
 
-      # variables beginning with _ are never saved out to file
-      # they are internal to the program
-      if attribute[0] == "_":
-        continue
+    for attribute in [a for a in self.__dict__ if a [0] != '_']:
+      val = self.__dict__ [attribute]
 
-      val = self.__dict__[attribute]
-      if lookupDict[xmlEntity].has_key('Attributes') and \
-         lookupDict[xmlEntity]['Attributes'].has_key(attribute):
+      if lookupDict [xmlEntity].has_key ('Attributes') and \
+         lookupDict [xmlEntity]['Attributes'].has_key (attribute):
+
+        attrDef = lookupDict [xmlEntity]['Attributes'][attribute]
+
         if val != None and \
-           (not 
lookupDict[xmlEntity]['Attributes'][attribute].has_key('Default') or \
-            (lookupDict[xmlEntity]['Attributes'][attribute]['Default']) != 
(val)):
-          typecast = lookupDict[xmlEntity]['Attributes'][attribute]['Typecast']
-          if typecast == GTypecast.boolean \
-             and val == 1:
+            (not 'Default' in attrDef or attrDef ['Default'] != (val)):
+
+          typecast = attrDef ['Typecast']
+          if typecast == GTypecast.boolean and val == 1:
             addl = ' %s=""' % (attribute)
           elif typecast == GTypecast.names:
-            addl = ' %s="%s"' % \
-                (attribute, string.join(val,','))
+            addl = ' %s="%s"' % (attribute, ','.join (val))
           else:
-            addl = ' %s="%s"' % (attribute, saxutils.escape('%s' % val))
+            addl = ' %s="%s"' % (attribute, saxutils.escape ('%s' % val))
+
           if len(addl) + pos > 78:
             xmlString += "\n" + " " * indent + addl
             pos = indent
           else:
             xmlString = xmlString + addl
-            pos += len(addl)
+            pos += len (addl)
 
     xmlString += ">\n"
     if self.format == 'base64':
-      xmlString += base64.encodestring(self.__data__)
+      xmlString += base64.encodestring (self.__data__)
     else:
-      raise "Unsupported binary format: %s" % self.format
-    xmlString += "%s</%s>\n" % (gap[:-2], xmlEntity)
+      raise UnsupportedFormatError, self.format
 
+    xmlString += "%s</%s>\n" % (gap [:-2], xmlEntity)
+
     return xmlString
 
 
-  def getChildrenAsContent(self):
+  # ---------------------------------------------------------------------------
+  # Return the children's content
+  # ---------------------------------------------------------------------------
+
+  def getChildrenAsContent (self):
+    """
+    A L{GBinary} instance cannot have children, so the result of this function
+    is just the same as the method L{get}.
+
+    @returns: the data of the object
+    """
+
     return self.__data__
 
+# =============================================================================
+# Return any XML elements associated with GBinary
+# =============================================================================
 
+def getXMLelements (updates={}):
+  """
+  Return any XML elements associated with GBinary
+  @returns: dictionary with all elements associated with GBinary
+  """
 
-#
-# Return any XML elements associated with
-# GTriggers.  Bases is a dictionary of tags
-# whose values are update dictionaries.
-# For example: bases={'datasource': {'BaseClass':myDataSource}}
-# sets xmlElements['datasource']['BaseClass'] = myDataSource
-#
-def getXMLelements(updates={}):
-
   xmlElements = {
       'binary': {
          'BaseClass': GBinary,
@@ -146,8 +225,7 @@
          'ParentTags': None },
       }
 
-  for alteration in updates.keys():
-    xmlElements[alteration].update(updates[alteration])
+  for alteration in updates.keys ():
+    xmlElements [alteration].update (updates [alteration])
 
   return xmlElements
-


Property changes on: trunk/gnue-common/src/definitions/GBinary.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: trunk/gnue-common/src/definitions/GObjects.py
===================================================================
--- trunk/gnue-common/src/definitions/GObjects.py       2005-11-11 18:27:31 UTC 
(rev 8095)
+++ trunk/gnue-common/src/definitions/GObjects.py       2005-11-15 13:35:43 UTC 
(rev 8096)
@@ -1,6 +1,9 @@
+# GNU Enterprise Common Library - GNUe XML object definitions
 #
-# This file is part of GNU Enterprise.
+# Copyright 2001-2005 Free Software Foundation
 #
+# This file is part of GNU Enterprise
+#
 # GNU Enterprise is free software; you can redistribute it
 # and/or modify it under the terms of the GNU General Public
 # License as published by the Free Software Foundation; either
@@ -16,64 +19,110 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# Copyright 2000-2005 Free Software Foundation
-#
-# FILE:
-# GObjects.py
-#
-# DESCRIPTION:
+# $Id$
+
 """
 Base class for GNUe objects which can be represented as XML
 """
-__revision__ = "$Id$"
 
+__all__ = ['GObj', 'ParserMultiplexor', 'GUndividedCollection']
+
 from xml.sax import saxutils
-from gnue.common.apps import GDebug
-import string
-import types
 from gnue.common.definitions.GParserHelpers import GContent, ParserObj
 from gnue.common.formatting import GTypecast
 from gnue.common.logic.GTriggerCore import GTriggerCore
 
-#
-# Class GObj
-#
-# Base class for GNUe objects which
-# can be represented by XML tags
-#
-class GObj(GTriggerCore, ParserObj):
+
+# =============================================================================
+# Base class for GNUe object which can be represented by XML tags
+# =============================================================================
+
+class GObj (GTriggerCore, ParserObj):
   """
-  The base class for almost all GNUe objects.
+  The base class for almost all GNUe objects. GObj based objects can be
+  represented by XML tags in a GParser based setup. This class introduces the
+  concept of phased initialization as well as dictionary style access.
 
-  GObj based objects can be represented by XML tags in a GParser
-  based setup.
+  This is the method of attribute access used by Designer and Reports.
+  For example. if foo is a GObject, then the following are equivalent::
+      foo.required = 'Y'
+      foo['required'] = 'Y'
+
+  The advantage of this method, however, is when namespaces are used
+  in the GObj XML document (i.e., reports). e.g., ::
+     foo['Char:x'] = 1
+     foo['Char:y'] = 2
+
+  These don't have a clean equivalent using the .attribute method.
+  (Though, technically, a tool could access foo.Char__x, but that
+  should be considered bad style.)
+
+  Eventually,  .attribute style access should probably be deprecated,
+  so we can clean up the python namespaces of GObjects. (i.e., we could
+  keep all XML-storable attributes in one dict instead of in the
+  namespace __dict__.
   """
-  def __init__(self, *args, **parms):
-    GTriggerCore.__init__(self)
-    ParserObj.__init__(self, *args, **parms)
+
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, *args, **parms):
+
+    GTriggerCore.__init__ (self)
+    ParserObj.__init__ (self, *args, **parms)
+
     self._inits = []
 
-  def buildObject(self, **params):
-    """
-    A convenience function for applications NOT using GParser to load an 
object tree.
 
+  # ---------------------------------------------------------------------------
+  # Dictionary style attribute access
+  # ---------------------------------------------------------------------------
+
+  def __getitem__ (self, key):
+
+    return self.__dict__ [key.replace (':', '__')]
+
+
+  # ---------------------------------------------------------------------------
+
+  def __setitem__ (self, key, value):
+
+    return self._setItemHook (key.replace (':', '__'), value)
+
+
+  # ---------------------------------------------------------------------------
+  # Build an object using attributes given as keyword arguments
+  # ---------------------------------------------------------------------------
+
+  def buildObject (self, **params):
     """
-    self.__dict__.update(params)
-    return self._buildObject()
+    A convenience function for applications NOT using GParser to load an object
+    tree.
+    """
 
+    self.__dict__.update (params)
+    return self._buildObject ()
 
-  def buildAndInitObject(self, **params):
+
+  # ---------------------------------------------------------------------------
+  # Build and initialize an object using attributes given as keyword arguments
+  # ---------------------------------------------------------------------------
+
+  def buildAndInitObject (self, **params):
     """
-    This is a convenience function for applications
-    NOT using GParser to load an object tree.
+    This is a convenience function for applications NOT using GParser to load
+    an object tree.
     """
-    self.phaseInit(self.buildObject(**params))
 
+    self.phaseInit (self.buildObject (**params))
 
-  #
+
+  # ---------------------------------------------------------------------------
   # phaseInit
-  #
-  def phaseInit(self, iterations=0):
+  # ---------------------------------------------------------------------------
+  
+  def phaseInit (self, iterations = 0):
     """
     Starts GNUe's phased initialization system from this object down.
 
@@ -100,21 +149,164 @@
     as the children may not be loaded yet or may not yet have the needed
     information.
 
-    @type iterations: integer
     @param iterations: Limits the number of passes to the specified number.
-                       This doesn't appear to be used anywhere.
     """
+
     if iterations == 0:
-      iterations = self.maxInits()
-    for phase in range(iterations):
-      self._phaseInit(phase)
+      iterations = self.maxInits ()
 
-  def _phaseInit(self, phase):
+    for phase in range (iterations):
+      self._phaseInit (phase)
+
+
+  # ---------------------------------------------------------------------------
+  # Get the maximium size of all the _inits lists
+  # ---------------------------------------------------------------------------
+
+  def maxInits (self):
     """
-    Used internally by phaseInit to walk through the
-    object tree initializing objects.
+    maxInits returns the maximum size of all the _inits list from this object
+    or it's children
     """
 
+    self._initCount = 0
+    self.walk (self.__maxInitsWalker)
+    return self._initCount
+
+  # ---------------------------------------------------------------------------
+
+  def __maxInitsWalker (self, object):
+    """
+    The function passed to the tree walker to extract the length of the _inits
+    list.
+
+    @param object: L{GObj} to the get the length of it's _inits sequence
+    """
+    if hasattr (object, '_inits'):
+      self._initCount = max (self._initCount, len (object._inits))
+
+  
+  # ---------------------------------------------------------------------------
+  # Show the XML tree of an object
+  # ---------------------------------------------------------------------------
+
+  def showTree (self, indent = 0):
+    """
+    A recusive function to print an indented text representation of the GObj
+    tree from this object down. This is usefull for debugging purposes.
+
+    @param indent: Sets the level of indention.  Used during recursion to
+      properly indent the tree.
+    @type indent: int
+    """
+
+    print ' ' * indent + `self._type`, self
+
+    for child in self._children:
+      child.showTree (indent + 2)
+
+
+  # ---------------------------------------------------------------------------
+  # Get the XML tag used to represent the object
+  # ---------------------------------------------------------------------------
+
+  def getXmlTag (self, stripPrefixes = None):
+    """
+    Returns the xml tag to be used to represent the object.
+
+    @param stripPrefixes: A list of prefixes that will automatically be removed
+      from the objects type.  This can be used to remove the gf from the start
+      of all the gnue-forms objects.  If set to None (the default) then the
+      behaviour will be the old style which removes the first two characters
+      from the type.
+
+    @returns: The XML tag to use
+    @rtype: string
+    """
+
+    if stripPrefixes is None:
+      return self._type [2:].replace ('_', '-').lower ()
+
+    for prefix in stripPrefixes:
+      if prefix == self._type [:len (prefix)]:
+        return self._type [len (prefix):].replace ('_', '-').lower ()
+
+    return self._type.replace ('_', '-').lower ()
+
+
+  # ---------------------------------------------------------------------------
+  # Function for traversing an object tree
+  # ---------------------------------------------------------------------------
+
+  def walk (self, function, *args, **parms):
+    """
+    Function that recursively walks down through a tree of L{ParserObj}
+    instances and applies a function to them.
+
+    @param function: the function to call for every element found in the tree
+    """
+
+    function (self, *args, **parms)
+    for child in self._children:
+      if isinstance (child, GObj):
+        child.walk (function, *args, **parms)
+
+
+  # ---------------------------------------------------------------------------
+  # Get an iterator for child objects
+  # ---------------------------------------------------------------------------
+
+  def iterator (self, test = None, types = (), includeSelf = True):
+    """
+    Return a python iterator of child objects.
+
+    @param test: A function that should return true or false to
+           indicate whether a GObject should be included in the
+           iterator. This method will be passed a GObj instance.
+           e.g., test=lambda obj: obj._type in ('GFField,'GFEntry')
+    @type test: method
+
+    @param types: A list of valid child types to return.
+           E.g., types=('GFField','GFEntry')
+    @type types: list
+
+    @param includeSelf: Should the current object be included in the tests?
+    @type includeSelf: boolean
+
+    @return: An iterator of matching objects
+
+    """
+    if includeSelf:
+      objects = [self]
+    else:
+      objects = self._children
+    set = []
+
+    def _includable (object):
+      include = True
+      if test:
+        include = include and test (object)
+      if types:
+        include = include and object._type in types
+      if include:
+        set.append (object)
+
+    for child in objects:
+      child.walk (_includable)
+
+    return _GObjectIterator (set)
+
+
+  # ---------------------------------------------------------------------------
+  # Worker function to perform an initialization
+  # ---------------------------------------------------------------------------
+
+  def _phaseInit (self, phase):
+    """
+    Used internally by phaseInit to walk through the object tree initializing
+    objects.
+    """
+
 ## TODO: Below is a call-less recursive version of
 ## TODO: phaseInit.  Needs to be profiled both ways.
 ## TODO: Profile tests have shown this to be .001
@@ -134,244 +326,201 @@
 ##        continue
 
     inits = self._inits
-    if (len(inits) > phase) and inits[phase]:
-      assert gDebug(7,"%s: Init Phase %s" % (self._type, phase+1))
-      inits[phase]()
+    if (len (inits) > phase) and inits [phase]:
+      assert gDebug (7,"%s: Init Phase %s" % (self._type, phase+1))
+      inits [phase] ()
 
     for child in self._children:
       try:
         initter = child._phaseInit
       except AttributeError:
         continue
-      initter(phase)
 
+      initter (phase)
 
-  def _buildObject(self):
-    """
-    # This function is called after the parsers have completely
-    # constructed. All children should be in place and
-    # attributes and content should be set at this point.
-    # Return the number of phaseInit iterations your object will
-    # need.
-    #
-    # NOTE: Do not initialize datasources, etc at this point.
-    #       This is only so content can be set, etc, after
-    #       loading from XML.
-    #
 
-    """
-    return len(self._inits)
+  # ---------------------------------------------------------------------------
+  # Get the number of phaseInit iterations needed by the object
+  # ---------------------------------------------------------------------------
 
-  def maxInits(self):
+  def _buildObject (self):
     """
-    maxInits returns the maximum size of all the _inits
-    list from this object or it's children
-    """
-    self._initCount = 0
-    self.walk(self._maxInitsWalker)
-    return self._initCount
+    This function is called after the parsers have completely constructed. All
+    children should be in place and attributes and content should be set at
+    this point.  Return the number of phaseInit iterations your object will
+    need.
 
-  def _maxInitsWalker(self, object):
-    """
-    The function passed to the tree walker to extract the
-    length of the _inits list.  Used by maxInits.
-    """
-    if hasattr(object, '_inits'):
-      self._initCount = max(self._initCount, len(object._inits))
+    NOTE: Do not initialize datasources, etc at this point. This is only so
+    content can be set, etc, after loading from XML.
 
-
-  def getChildrenAsContent(self):
+    @returns: number of the phaseInit iterations needed by this object
     """
-    Returns the content of any GContent objects that are children
-    of this object.
 
-    @rtype: string or binary(?)
-    @return: The contents of the children
-    """
+    return len (self._inits)
 
-    # This is down here to avoid recursive importing
-    from gnue.common.definitions.GBinary import GBinary
 
-    content = ""
-    for child in self._children:
-      if isinstance(child, GContent):
-        content += child._content
-      elif isinstance(child, GBinary):
-        content += child.__data__
-    return content
+  # ---------------------------------------------------------------------------
+  # callback function called when an item has been changed
+  # ---------------------------------------------------------------------------
 
-  def showTree(self, indent=0):
+  def _setItemHook (self, key, value):
     """
-    A recusive function to print an indented text representation of
-    the GObj tree from this object down.
+    This bit of nastiness is here to let GNUe Designer capture the setting of
+    GObject properties. This is primarily used in the wizard system so Designer
+    can act in real time as a wizard sets a document's properties.
 
-    This is usefull for debugging purposes.
+    I.e., if a wizard sets::
+      field['width'] = 10
 
-    @param indent: Sets the level of indention.  Used during recursion
-    to properly indent the tree.
-    @type indent: int
+    Designer can immediately changed the visual width of the field as displayed
+    on screen.
     """
-    print ' ' * indent + `self._type`, self
+    self.__dict__ [key] = value
 
-    for child in self._children:
-      child.showTree(indent + 2)
 
-  #
-  # addChild
-  #
-  #
-  def addChild(self, child):
-    """
-    Adds an object to an instances list of children
+  # ---------------------------------------------------------------------------
+  # Implementation of virtual methods
+  # ---------------------------------------------------------------------------
 
-    @type child: GObj derived class
-    @param child: The object to add.
+  def _dumpXML_ (self, lookupDict, treeDump, gap, xmlnamespaces, textEncoding,
+            stripPrefixes, escape):
     """
-    self._children.append(child)
-
-  def getXmlTag(self, stripPrefixes=None):
+    Dumps an XML representation of the object
     """
-    Returns the xml tag to be used to represent the object.
 
-    @param stripPrefixes: A list of prefixes that will automatically
-                          be removed from the objects type.  This can be
-                          used to remove the gf from the start of all
-                          the gnue-forms objects.  If set to None (the default)
-                          then the behaviour will be the old style which
-                          removes the first two characters from the type.
-    @return: The xml tag to use
-    @rtype: string
-    """
-    if stripPrefixes == None:
-      return string.lower(string.replace(self._type[2:], '_', '-'))
-    for prefix in stripPrefixes:
-      if prefix == self._type[:len(prefix)]:
-        return string.lower(string.replace(self._type[len(prefix):], '_', '-'))
-    return string.lower(string.replace(self._type, '_', '-'))
-
-  def dumpXML(self, lookupDict, treeDump=None, gap="  ", xmlnamespaces={},
-              textEncoding='<locale>', stripPrefixes=None):
-    """
-    Dumps an XML representation of the object
-    """
-    xmlns = ""
+    xmlns    = ""
     xmlnsdef = ""
 
-    if textEncoding=='<locale>':
-      textEncoding=gConfig('textEncoding')
+    if textEncoding == '<locale>':
+      textEncoding = gConfig('textEncoding')
 
     try:
       if self._xmlnamespace:
         try:
-          xmlns = xmlnamespaces[self._xmlnamespace] + ":"
+          xmlns = xmlnamespaces [self._xmlnamespace] + ":"
+
         except KeyError:
-          i = 0
+          i     = 0
           xmlns = "out"
-          while xmlns in xmlnamespaces.values():
-            i += 1
+
+          while xmlns in xmlnamespaces.values ():
+            i    += 1
             xmlns = "out%s" % i
-          xmlnamespaces[self._xmlnamespace] = xmlns
+
+          xmlnamespaces [self._xmlnamespace] = xmlns
           xmlnsdef = ' xmlns:%s="%s"' % (xmlns, self._xmlnamespace)
-          xmlns += ":"
+          xmlns   += ":"
+
     except AttributeError:
       try:
         if self._xmlchildnamespace:
-          if not xmlnamespaces.has_key(self._xmlchildnamespace):
-            i = 0
+          if not xmlnamespaces.has_key (self._xmlchildnamespace):
+            i  = 0
             ns = "out"
-            while ns in xmlnamespaces.values():
+
+            while ns in xmlnamespaces.values ():
               i += 1
               ns = "out%s" % i
-            xmlnamespaces[self._xmlnamespace] = ns
+
+            xmlnamespaces [self._xmlnamespace] = ns
             xmlnsdef = ' xmlns:%s="%s"' % (ns, self._xmlchildnamespace)
+
       except AttributeError:
         pass
 
     try:
       if self._xmlchildnamespaces:
-        for abbrev in self._xmlchildnamespaces.keys():
-          xmlnsdef += ' xmlns:%s="%s"' % (abbrev, 
self._xmlchildnamespaces[abbrev])
+        for abbrev in self._xmlchildnamespaces.keys ():
+          xmlnsdef += ' xmlns:%s="%s"' % \
+              (abbrev, self._xmlchildnamespaces [abbrev])
+
     except AttributeError:
       pass
 
-    xmlEntity = self.getXmlTag(stripPrefixes)
+    xmlEntity = self.getXmlTag (stripPrefixes)
     xmlString = "%s<%s%s%s" % (gap[:-2], xmlns, xmlEntity, xmlnsdef)
 
-    indent = len(xmlString)
-    pos = indent
-    attrs = self.__dict__.keys()
-    attrs.sort()
+    indent = len (xmlString)
+    pos    = indent
+    attrs  = self.__dict__.keys ()
+    attrs.sort ()
 
     # Make 'name' first
     if 'name' in attrs:
-      attrs.pop(attrs.index('name'))
-      attrs.insert(0, 'name')
+      attrs.pop (attrs.index ('name'))
+      attrs.insert (0, 'name')
 
-    for attribute in attrs:
-      # skip keys beginning with _
-      if attribute[0] == "_":
-        continue
+    # Iterate over all attributes which do not start with an underscore
+    for attribute in [a for a in attrs if a [0] != "_"]:
+      val = self.__dict__ [attribute]
 
-      val = self.__dict__[attribute]
       if (xmlns and attribute in self._listedAttributes) or \
-         (not xmlns and lookupDict[xmlEntity].has_key('Attributes') and \
-         lookupDict[xmlEntity]['Attributes'].has_key(attribute)):
+         (not xmlns and lookupDict [xmlEntity].has_key ('Attributes') and \
+         lookupDict [xmlEntity]['Attributes'].has_key (attribute)):
+
+        attrDef = lookupDict [xmlEntity]['Attributes'][attribute]
+
         if val != None and \
-           (xmlns or (not 
lookupDict[xmlEntity]['Attributes'][attribute].has_key('Default') or \
-            (lookupDict[xmlEntity]['Attributes'][attribute]['Default']) != 
(val))):
+           (xmlns or (not 'Default' in attrDef or \
+           (attrDef ['Default']) != (val))):
 
-          try:
-            typecast = 
lookupDict[xmlEntity]['Attributes'][attribute]['Typecast']
-          except:
-            typecast = GTypecast.text
+          typecast = attrDef.get ('Typecast', GTypecast.text)
 
           if typecast == GTypecast.boolean:
-            if val:
-              addl = ' %s="Y"' % (attribute)
-            else:
-              addl = ' %s="N"' % (attribute)
+            addl = ' %s="%s"' % (attribute, ['N', 'Y'][bool (val)])
+
           elif typecast == GTypecast.names:
-            if type(val) == types.StringType:
-              #addl = ' %s="%s"' % (attribute, 
string.join(val.decode(textEncoding), ','))
-              addl = ' %s="%s"' % (attribute, string.join(unicode(val, 
textEncoding), ','))
+            if isinstance (val, (list, tuple)):
+              addl = ' %s="%s"' % (attribute, ','.join (val))
+            elif isinstance (val, string):
+              addl = ' %s="%s"' % (attribute, unicode (val, textEncoding))
             else:
-              addl = ' %s="%s"' % (attribute, string.join(val, ','))
+              addl = ' %s="%s"' % (attribute, val)
+
           else:
-            if type(val) == types.StringType:
-              #addl = ' %s="%s"' % (attribute, saxutils.escape('%s' % 
val.decode(textEncoding)))
-              addl = ' %s="%s"' % (attribute, saxutils.escape('%s' % 
unicode(val, textEncoding)))
-            else:
-              addl = ' %s="%s"' % (attribute, saxutils.escape('%s' % val))
+            cont = '%s' % val
+            if isinstance (val, str):
+              cont = unicode (val, textEncoding)
 
-          if len(addl) + pos > 78:
+            addl = ' %s="%s"' % (attribute, saxutils.escape (cont))
+
+          if len (addl) + pos > 78:
             xmlString += "\n" + " " * indent + addl
-            pos = indent
+            pos        = indent
           else:
             xmlString += addl
-            pos += len(addl)
+            pos       += len (addl)
 
-      if attribute.find('__') > 0 and attribute.split('__')[0] in 
xmlnamespaces.keys():
+      if attribute.find ('__') > 0 and \
+          attribute.split ('__') [0] in xmlnamespaces:
+
         if val != None:
-          if type(val) == types.StringType:
-            addl = ' %s="%s"' % (attribute.replace('__', ':'), 
saxutils.escape('%s' % unicode(val, textEncoding)))
+          attrName  = attribute.replace ('__', ':')
+          attrValue = val
+
+          if isinstance (val, str):
+            attrValue = unicode (val, textEncoding)
           else:
             try:
-              if val == int(val):
-                val = int(val)
+              if val == int (val):
+                attrValue = int (val)
+
             except:
               pass
-            addl = ' %s="%s"' % (attribute.replace('__', ':'), 
saxutils.escape('%s' % val))
-          if len(addl) + pos > 78:
+
+          addl = ' %s="%s"' % (attrName, saxutils.escape ('%s' % attrValue))
+
+          if len (addl) + pos > 78:
             xmlString += "\n" + " " * indent + addl
             pos = indent
           else:
             xmlString += addl
-            pos += len(addl)
+            pos += len (addl)
 
-    if len(self._children):
+    if len (self._children):
       hasContent = 0
       for child in self._children:
-        hasContent = hasContent or isinstance(child, GContent)
+        hasContent = hasContent or isinstance (child, GContent)
       if hasContent:
         xmlString += ">"
       else:
@@ -379,250 +528,73 @@
 
       if treeDump:
         for child in self._children:
-          xmlString += child.dumpXML(lookupDict, 1, gap+"  ",
-              textEncoding=textEncoding, xmlnamespaces=xmlnamespaces, 
stripPrefixes=stripPrefixes)
+          xmlString += child.dumpXML (lookupDict, True, gap + "  ",
+                                    xmlnamespaces, textEncoding, stripPrefixes)
 
       if hasContent:
         xmlString += "</%s%s>\n" % (xmlns, xmlEntity)
       else:
-        xmlString += "%s</%s%s>\n" % (gap[:-2], xmlns, xmlEntity)
+        xmlString += "%s</%s%s>\n" % (gap [:-2], xmlns, xmlEntity)
+
     else:
       xmlString += "/>\n"
 
     return xmlString
 
 
-  def walk(self, function, *args, **parms):
-    """
-    Function that recursively walks down through a tree of GObj
-    instances and applies a function to them.
-    """
-    function(self, *args, **parms)
-    for child in self._children:
-      if isinstance(child, GObj):
-        child.walk(function, *args, **parms)
 
-  def iterator(self, test=None, types=(), includeSelf=True):
-    """
-    Return a python iterator of child objects.
+# =============================================================================
+# ParserMultiplexor
+# =============================================================================
 
-    @param test: A function that should return true or false to
-           indicate whether a GObject should be included in the
-           iterator. This method will be passed a GObj instance.
-           e.g., test=lambda obj: obj._type in ('GFField,'GFEntry')
-    @type test: method
+class ParserMultiplexor (ParserObj):
+  """
+  When a GParser's BaseClass needs to be dependent upon an attribute, the tool
+  can use a customized ParserMultiplexor, overwriting the getClass method.
 
-    @param types: A list of valid child types to return.
-           E.g., types=('GFField','GFEntry')
-    @type types: list
-
-    @param includeSelf: Should the current object be included in the tests?
-    @type includeSelf: boolean
-
-    @return: An iterator of matching objects
-
-    """
-    if includeSelf:
-      objects = [self]
+  e.g., assume we have a XML tag 'goblin', that corresponds to a GObj-based
+  class Goblin.  However, if <goblin style="boo"> we really need a BooGoblin
+  object or if <goblin style="foo"> then we need a FooBoblin object, then the a
+  GoblinPlexor would define getClass as:
+ 
+  def getClass (self):
+    if self.style == 'boo':
+      return BooGoblin
+    elif self.style == 'foo':
+      return FooGoblin
     else:
-      objects = self._children
-    set = []
+      return Goblin
+  """
 
-    def _includable(object):
-      include = True
-      if test:
-        include = include and test(object)
-      if types:
-        include = include and object._type in types
-      if include:
-        set.append(object)
+  # ---------------------------------------------------------------------------
+  # Build an object
+  # ---------------------------------------------------------------------------
 
-    for child in objects:
-      child.walk(_includable)
+  def _buildObject (self):
 
-    return _GObjectIterator(set)
+    newObj = self.getClass ()(None)
+    for attr, value in self.__dict__.items ():
+      if attr not in ('_buildObject', 'getClass') and attr [:2] != '__':
+        newObj.__dict__ [attr] = value
 
-  def findParentOfType(self, parentType, includeSelf=1):
-    """
-    Moves upward though the parents of an object till
-    it finds the parent of the specified type
-    """
-    if includeSelf:
-      parentObject = self
-    else:
-      parentObject = self.getParent ()
+    parent = self.getParent ()
+    if parent:
+      parent._children [parent._children.find (self)] = newObj
 
-    while 1:
-      if parentObject == None:
-        return None
-      elif parentObject._type == parentType:
-        return parentObject
+    return newObj._buildObject (self)
 
-      # If passed a type of NONE it finds the top object in the tree
-      if not parentType and not parentObject.getParent ():
-        return parentObject
 
-      parentObject = parentObject.getParent ()
+  # ---------------------------------------------------------------------------
+  # This should return a GObj-based class
+  # ---------------------------------------------------------------------------
 
-  def findChildNamed(self, name, childType = None):
+  def getClass (self):
     """
-    Moves downward though the children of an object till
-    it finds the child with the specified name.
+    Get the actual class to instanciate for this XML element
 
-    @param name: The name to search for
-    @param childType: The type of object to search for, if None then any type
-                 will match.
-    @return: The child with the matching name, or None if child not found
+    @returns: class to be used for this XML element
     """
 
-    for child in self._children:
-      if child.name == name:
-        if childType is None or child._type == childType:
-          return child
-
-    return None
-
-  def findChildOfType(self, childType, includeSelf=1, allowAllChildren=0):
-    """
-    Moves downward though the children of an object till
-    it finds the child of the specified type
-
-    """
-
-    if includeSelf and self._type == childType:
-      return self
-
-    for child in self._children:
-      if child._type == childType:
-        return child
-
-    if allowAllChildren:
-      for child in self._children:
-        o = child.findChildOfType(childType, 0, 1)
-        if o:
-          return o
-
-    return None
-
-
-  def findChildrenOfType(self, childType, includeSelf=1, allowAllChildren=0):
-    """
-    find all children of a specific type
-    """
-    rs = []
-
-    if includeSelf and self._type == childType:
-      rs += [self]
-
-    for child in self._children:
-      if child._type == childType:
-        rs += [child]
-
-    if allowAllChildren:
-      for child in self._children:
-        try:
-          rs += child.findChildrenOfType(childType, 0, 1)
-        except AttributeError:
-          pass  # not all children will be GObj and support that function
-
-    return rs
-
-
-  def getDescription(self):
-    """
-    Return a useful description of the object.
-    Currently used by GNUe Designer.
-    """
-    if hasattr(self, '_description'):
-      return self._description
-    elif hasattr(self, 'name'):
-      return self.name + " (%s)" % self._type[2:]
-    else:
-      return self._type[2:] + " (%s)" % self._type[2:]
-
-  # ===========================================================================
-  # Dictionary-style access to GObject attributes (namespace-safe)
-  # ===========================================================================
-  """
-  This is the method of attribute access used by Designer and Reports.
-  For example. if foo is a GObject, then the following are equivalent:
-      foo.required = 'Y'
-      foo['required'] = 'Y'
-
-  The advantage of this method, however, is when namespaces are used
-  in the GObj XML document (i.e., reports). e.g., :
-     foo['Char:x'] = 1
-     foo['Char:y'] = 2
-  These don't have a clean equivalent using the .attribute method.
-  (Though, technically, a tool could access foo.Char__x, but that
-  should be considered bad style.)
-
-  Eventually,  .attribute style access should probably be deprecated,
-  so we can clean up the python namespaces of GObjects. (i.e., we could
-  keep all XML-storable attributes in one dict instead of in the
-  namespace __dict__.
-  """
-  def __getitem__(self, key):
-    return self.__dict__[key.replace(':', '__')]
-
-  def __setitem__(self, key, value):
-    return self._setItemHook(key.replace(':', '__'), value)
-
-  def _setItemHook(self, key, value):
-    """
-    This bit of nastiness is here to let GNUe Designer
-    capture the setting of GObject properties. This is
-    primarily used in the wizard system so Designer
-    can act in real time as a wizard sets a document's
-    properties.
-
-    I.e., if a wizard sets::
-      field['width'] = 10
-
-    Designer can immediately changed the visual width
-    of the field as displayed on screen.
-    """
-    self.__dict__[key] = value
-
-
-#
-# ParserMultiplexor
-#
-# When a GParser's BaseClass needs to be dependent upon
-# an attribute, the tool can use a customized ParserMultiplexor,
-# overwriting the getClass method.
-#
-# e.g., assume we have an xml tag 'goblin', that
-# corresponds to a GObj-based class Goblin.  However,
-# if <goblin style="boo"> we really need a BooGoblin
-# object or if <goblin style="foo"> then we need a
-# FooBoblin object, then the a GoblinPlexor would
-# define getClass as:
-#
-# def getClass(self):
-#   if self.style == 'boo':
-#     return BooGoblin
-#   elif self.style == 'foo':
-#     return FooGoblin
-#   else:
-#     return Goblin
-#
-class ParserMultiplexor(ParserObj):
-
-  def _buildObject(self):
-    newObj = self.getClass()(None)
-    for attr, value in self.__dict__.items():
-      if attr not in ('_buildObject', 'getClass') and attr[:2] != '__':
-        newObj.__dict__[attr] = value
-
-    parent = self.getParent ()
-    if parent:
-      parent._children [parent._children.find (self)] = newObj
-    return newObj._buildObject (self)
-
-
-  # This should return a GObj-based class
-  def getClass(self):
     raise "Virtual method not implemented"
 
 
@@ -632,6 +604,10 @@
 
 class GUndividedCollection (GObj):
   """
+  GUndividedCollection implements a collection class where the children in a
+  diff () won't get divided. Example: A primary key definition can contain
+  multiple primary key fields. If a primary key definition differs from another
+  one, it's fields must be kept as a union.
   """
 
   # 
----------------------------------------------------------------------------
@@ -649,7 +625,21 @@
   # 
----------------------------------------------------------------------------
 
   def diff (self, goal, maxIdLength):
+    """
+    Build an object tree representing the difference between two object trees.
 
+    @param goal: L{ParserObj} tree to compare this object's tree to.
+    @param maxIdLength: if defined, use only up to maxIdLength characters of
+      the object name to check for identity.
+    @returns: L{ParserObj} tree representing the difference. Every object in
+      this tree has an additional attribute B{_action} which can contain one of
+      the following values:
+
+      * add: the object is only available in the 'goal' tree
+      * change: the object is avaialable in both trees, but differs
+      * remove: the object is only available in the 'source' tree
+    """
+
     result = ParserObj.diff (self, goal, maxIdLength)
 
     if result is not None:
@@ -680,18 +670,49 @@
 
 
 # =============================================================================
-# Convenience class for the GObject .iterator() method
+# Convenience class for the GObject .iterator () method
 # =============================================================================
+
 class _GObjectIterator:
-  def __init__(self, set):
-    self.stack = set[:]
+  """
+  Convenience class for L{GObj.iterator} method providing an iterator over a
+  given set of L{GObj} instances (children).
+  """
 
-  def __iter__(self):
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, set):
+
+    self.stack = set [:]
+
+
+  # ---------------------------------------------------------------------------
+  # Return the iterator object
+  # ---------------------------------------------------------------------------
+
+  def __iter__ (self):
+    """
+    @returns: the iterator object itself.
+    """
+
     return self
 
-  def next(self):
+
+  # ---------------------------------------------------------------------------
+  # Get the next item
+  # ---------------------------------------------------------------------------
+
+  def next (self):
+    """
+    Return the next item from the container.
+    @returns: the next item from the container
+    @raises StopIteration: If no more items are available in the container.
+    """
+
     if self.stack:
-      return self.stack.pop(0)
+      return self.stack.pop (0)
     else:
       raise StopIteration
 

Modified: trunk/gnue-common/src/definitions/GParser.py
===================================================================
--- trunk/gnue-common/src/definitions/GParser.py        2005-11-11 18:27:31 UTC 
(rev 8095)
+++ trunk/gnue-common/src/definitions/GParser.py        2005-11-15 13:35:43 UTC 
(rev 8096)
@@ -1,6 +1,9 @@
+# GNU Enterprise Common Library - GNUe XML object definitions - XML Parser
 #
-# This file is part of GNU Enterprise.
+# Copyright 2001-2005 Free Software Foundation
 #
+# This file is part of GNU Enterprise
+#
 # GNU Enterprise is free software; you can redistribute it
 # and/or modify it under the terms of the GNU General Public
 # License as published by the Free Software Foundation; either
@@ -16,18 +19,15 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# Copyright 2000-2005 Free Software Foundation
-#
-# FILE:
-# GParser.py
-#
-# DESCRIPTION:
+# $Id: $
+
 """
 Class that contains a SAX2-based XML processor for GNUe
 """
-# NOTES:
-#
 
+__all__ = ['MarkupError', 'loadXMLObject', 'normalise_whitespace',
+           'xmlHandler', 'GImportItem', 'GImport']
+
 import sys, copy, types
 from gnue.common.definitions.GObjects import GObj
 from gnue.common.definitions.GRootObj import GRootObj
@@ -38,6 +38,7 @@
   from xml.sax.handler import property_lexical_handler
   from xml.sax import saxutils
   import xml.sax
+
 except ImportError:
   print """
    This GNUe tool requires pythons XML module be installed.
@@ -58,11 +59,11 @@
 from gnue.common.definitions.GParserHelpers import GContent, GComment
 
 
-#######################################################
-#
-# Error classed raised for markup errors
-#
-class MarkupError(errors.ApplicationError):
+# =============================================================================
+# Exceptions
+# =============================================================================
+
+class MarkupError (errors.ApplicationError):
   def __init__ (self, message, url = None, line = None):
     errors.ApplicationError.__init__ (self, message)
     text = [message]
@@ -78,34 +79,30 @@
     self.detail = string.join (text, os.linesep)
 
 
-#######################################################
-#
-# loadXMLObject
-#
-# This method loads an object from an XML file and
-# returns that object.  If initialize is 1 (default),
-# then the object is initialized and ready to go.
-# Setting initialize to 0 is useful for a design
-# environment where the object is not actually
-# being used, but simply loaded as a document.
-#
-# "attributes" is a dictionary containing extra
-# attributes that should be attached to this object.
-#
-#  e.g., if attributes={myproperty:[0,1,2]}, then
-#    before the object is initialized or returned,
-#    object.myproperty == [0,1,2].
-#
-#######################################################
+# -----------------------------------------------------------------------------
+# Build an object from a XML stream
+# -----------------------------------------------------------------------------
 
-def loadXMLObject(stream, handler, rootType, xmlFileType,
-    initialize=True, attributes={}, initParameters={}, url = None):
+def loadXMLObject (stream, handler, rootType, xmlFileType,
+    initialize = True, attributes = {}, initParameters = {}, url = None):
+  """
+  This method loads an object from a XML stream and returns that object.  If
+  initialize is True (default), then the object is initialized and ready to go.
+  Setting initialize to 0 is useful for a design environment where the object
+  is not actually being used, but simply loaded as a document.
 
+  "attributes" is a dictionary containing extra attributes that should be
+  attached to this object.
+
+  e.g., if attributes={myproperty:[0,1,2]}, then before the object is
+  initialized or returned, object.myproperty == [0,1,2].
+  """
+
   # Create a parser
-  parser = xml.sax.make_parser()
+  parser = xml.sax.make_parser ()
 
   # Set up some namespace-related stuff for the parsers
-  parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+  parser.setFeature (xml.sax.handler.feature_namespaces, 1)
 
   # Allow for parameter external entities
   ## Does not work with expat!!! ##
@@ -125,13 +122,13 @@
   dh.url = url
   dh.parser = parser
 
-  dh.initValidation()
+  dh.initValidation ()
 
   # Tell the parser to use our handler
-  parser.setContentHandler(dh)
+  parser.setContentHandler (dh)
 
   try:
-    parser.setProperty(property_lexical_handler, dh)
+    parser.setProperty (property_lexical_handler, dh)
   except Exception, e:
     print e
 
@@ -141,7 +138,7 @@
   except xml.sax.SAXParseException, e:
     raise MarkupError, (errors.getException () [2], url, e.getLineNumber ())
 
-  object = dh.getRoot()
+  object = dh.getRoot ()
 
   if not object:
     tmsg = u_("Error loading %s: empty definition file") % (xmlFileType)
@@ -155,7 +152,7 @@
               'got'     : object._type}
     raise MarkupError, (tmsg, url)
 
-  object._rootComments = dh.getRootComments()
+  object._rootComments = dh.getRootComments ()
 
   dh.finalValidation ()
 
@@ -167,66 +164,67 @@
   #
   #object.__dict__.update(attributes)
 
-  object.walk(addAttributesWalker,attributes=attributes)
+  object.walk (__addAttributesWalker, attributes = attributes)
 
   if initialize:
-    assert gDebug (7, "Initializing the object tree starting at %s" %(object))
-    object.phaseInit(dh._phaseInitCount)
+    assert gDebug (7, "Initializing the object tree starting at %s" % (object))
+    object.phaseInit (dh._phaseInitCount)
 
   # Break the cyclic reference in the content handler, so garbage collection is
   # able to collect it
   dh.parser = None
 
   return object
-#######################################################
-#
-# addAttributesWalker
-#
-#######################################################
-def addAttributesWalker(object, attributes={}):
-  if isinstance(object,GRootObj):
-    object.__dict__.update(attributes)
 
 
+# -----------------------------------------------------------------------------
 
-#######################################################
-#
-# normalise_whitespace
-#
-# Remove redundant whitespace from a string ( from xml-howto )
-#
-#######################################################
-def normalise_whitespace(text):
-  return string.join( string.split(text), ' ')
+def __addAttributesWalker (object, attributes = {}):
 
+  if isinstance (object, GRootObj):
+    object.__dict__.update (attributes)
 
-def default(attrs, key, default):
-  try:
-    return attrs[key]
-  except KeyError:
-    return default
 
+# ---------------------------------------------------------------------------
+# Remove redundant whitespace characters from a string
+# ---------------------------------------------------------------------------
 
-#######################################################
-#
-# xmlHandler
-#
-# This class is called by the XML parser to
-# process the xml file.
-#
-#######################################################
-class xmlHandler(xml.sax.ContentHandler):
+def normalise_whitespace (text):
+  """
+  Remove redundant whitespace characters from a string.
 
-  # Set to default namespace (which would be dropped)
-  # i.e., if default namespace is "Foo", then <Foo:test> would
-  # just be processed as <test>.
-  default_namespace = None
+  @param text: string to remove redundant whitespaces (space, tabs, ...)
+  @returns: normalized string
+  """
 
-  # Drop any elements that have a namespaces we don't know about?
+  return ' '.join (text.split ())
+
+
+# =============================================================================
+# XML Content handler 
+# =============================================================================
+
+class xmlHandler (xml.sax.ContentHandler):
+  """
+  This class is used by the XML parser to process the XML file.
+
+  @cvar default_namespace: The default namespace (which would be dropped), i.e.
+    if the default namespace is 'Foo', then <Foo:test> would just be processed
+    as <test>.
+  @cvar ignore_unknown_namespaces: If set to True, any elements that have an
+    unknown namespace will be dropped.
+  """
+
+  default_namespace         = None
   ignore_unknown_namespaces = False
 
-  def __init__(self):
 
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self):
+
     self.xmlElements = {}
 
     # This is a hack, currently used only by GRPassThru
@@ -236,83 +234,115 @@
     self.xmlNamespaceAttributesAsPrefixes = False
 
     # Internal stuff
-    self.xmlStack = []
-    self.nameStack = []
-    self.bootstrapflag = False
-    self.uniqueIDs = {}
-    self.root = None
-    self._phaseInitCount = 0
+    self.xmlStack        = []
+    self.nameStack       = []
+    self.bootstrapflag   = False
+    self.uniqueIDs       = {}
+    self.root            = None
+    self.url             = None
+    self.doImportLayoutParser = True
 
-    self._requiredTags = []
+    self._phaseInitCount     = 0
+    self._requiredTags       = []
     self._singleInstanceTags = []
-    self._tagCounts = {}
-    self.url = None
-    self._rootComments = []
-    self.doImportLayoutParser = True
+    self._tagCounts          = {}
+    self._rootComments       = []
 
-  #
+
+  # ---------------------------------------------------------------------------
   # Called by client code to get the "root" node
-  #
-  def getRoot(self):
+  # ---------------------------------------------------------------------------
+
+  def getRoot (self):
+    """
+    @returns: the root node of the object tree
+    """
+
     return self.root
 
-  #
+
+  # ---------------------------------------------------------------------------
   # Builds structures need to verify requirements in the file
-  #
-  def initValidation(self):
-    #
-    # Build list of tags along with a list of
-    # require tags
-    #
-    for element in self.xmlElements.keys():
-      self._tagCounts[element] = 0
+  # ---------------------------------------------------------------------------
+
+  def initValidation (self):
+    """
+    Update some statistics about the elements in use. All 'required' elements
+    will be added to the sequence L{_requiredTags} and all elements having
+    a True value set for 'SingleInstance' will be added to the sequence
+    L{_singleInstanceTags}. Additionally the tag-counter dictionary will
+    be reset.
+    """
+   
+    for element in self.xmlElements:
+      self._tagCounts [element] = 0
       try:
-        if self.xmlElements[element]['Required'] == 1:
-          self._requiredTags.append(element)
+        if self.xmlElements [element]['Required']:
+          self._requiredTags.append (element)
+          
       except KeyError:
         pass
 
       try:
-        if self.xmlElements[element]['SingleInstance'] == 1:
-          self._singleInstanceTags.append(element)
+        if self.xmlElements [element]['SingleInstance']:
+          self._singleInstanceTags.append (element)
+
       except KeyError:
         pass
 
-  def finalValidation(self):
+
+  # ---------------------------------------------------------------------------
+  # Final validation
+  # ---------------------------------------------------------------------------
+
+  def finalValidation (self):
+    """
+    Perform a final validation of the tags. Checks if all required tags are
+    really defined (via tag-counter dictionary).
+    """
+
     # TODO: too simple a validation need to be per object instance
     #for element in self._singleInstanceTags:
     #  if self._tagCounts[element] > 1:
-    #    raise MarkupError, _("File has multiple instances of <%s> when only 
one allowed") % (element)
+    #    raise MarkupError, \
+    #      _("File has multiple instances of <%s> when only one allowed") \
+    #      % (element)
 
     for element in self._requiredTags:
-      if self._tagCounts[element] < 1:
-        tmsg = u_("File is missing required tag <%s>") % (element)
-        raise MarkupError, (tmsg, self.url)
+      if self._tagCounts [element] < 1:
+        raise MarkupError, \
+            (u_("File is missing required tag <%s>") % element, self.url)
 
 
-  #
-  # Called by the internal SAX parser whenever
-  # a starting XML element/tag is encountered.
-  #
-  def startElementNS(self, qtag, qname, saxattrs):
+  # ---------------------------------------------------------------------------
+  # Start of a XML element
+  # ---------------------------------------------------------------------------
 
-    ns, name = qtag
-    attrs = {}
+  def startElementNS (self, qtag, qname, saxattrs):
+    """
+    Called by the internal SAX parser whenever a starting XML tag is
+    encountered.
+    """
+
+    ns, name       = qtag
+    attrs          = {}
     loadedxmlattrs = {}
-    baseAttrs = {}
+    baseAttrs      = {}
 
     # Updating self.xmlElements with namespace specific parser definitions
     # to let designer handle layout tags.
     if self.default_namespace is None and self.doImportLayoutParser and ns:
       try:
-        gnue, tool, toolNS = ns.split(':')
-        layoutParser = dyn_import('gnue.%s.adapters.filters.%s.LayoutParser' % 
\
-                                  (tool.lower(), toolNS))
-        self.xmlElements.update(layoutParser.getXMLelements())
+        gnue, tool, toolNS = ns.split (':')
+        layoutParser = dyn_import ('gnue.%s.adapters.filters.%s.LayoutParser' \
+                                   % (tool.lower (), toolNS))
+        self.xmlElements.update (layoutParser.getXMLelements ())
         self.default_namespace = ns
+
       except:
         self.doImportLayoutParser = False
-        assert gDebug (7, "No parser defined for namespace %s, using PassThru 
objects." % ns)
+        assert gDebug (7, "No parser defined for namespace %s, " \
+                          "using PassThru objects." % ns)
 
     if not ns or ns == self.default_namespace:
       #
@@ -321,7 +351,7 @@
       assert gDebug (7, "<%s>" % name)
 
       try:
-        baseAttrs = self.xmlElements[name].get('Attributes',{})
+        baseAttrs = self.xmlElements [name].get ('Attributes', {})
 
       except KeyError:
         raise MarkupError, \
@@ -331,47 +361,36 @@
 
       xmlns = {}
 
-      for qattr in saxattrs.keys():
+      for qattr in saxattrs.keys ():
         attrns, attr = qattr
 
         if attrns:
           if not self.xmlNamespaceAttributesAsPrefixes:
             tmsg = _("Unexpected namespace on attribute")
             raise MarkupError, (tmsg, self.url, self.parser.getLineNumber ())
-          prefix = attrns.split(':')[-1]
-          attrs[prefix + '__' + attr] = saxattrs[qattr]
-          xmlns[prefix] = attrns
+          prefix = attrns.split (':') [-1]
+          attrs [prefix + '__' + attr] = saxattrs [qattr]
+          xmlns [prefix] = attrns
 
-          loadedxmlattrs[attr] = saxattrs[qattr]
+          loadedxmlattrs [attr] = saxattrs [qattr]
 
         else:
-
           # Typecasting, anyone?  If attribute should be int, make it an int
           try:
-            attrs [attr] = baseAttrs [attr].get ('Typecast', 
GTypecast.text)(saxattrs[qattr])
-            loadedxmlattrs[attr] = attrs[attr]
+            typecast     = baseAttrs [attr].get ('Typecast', GTypecast.text)
+            attrs [attr] = typecast (saxattrs [qattr])
+            loadedxmlattrs [attr] = attrs [attr]
+
           except KeyError:
             raise MarkupError, \
                 (u_('Error processing <%(tagname)s> tag [I do not '
                    'recognize the "%(attribute)s" attribute]') \
-                % {'tagname': name,
-                   'attribute': attr}, self.url, self.parser.getLineNumber ())
+                 % {'tagname': name, 'attribute': attr},
+                 self.url, self.parser.getLineNumber ())
 
-          # this error shouldn't occure anymore
-          #except UnicodeError:
-          #  tmsg = _('Error processing <%s> tag [Encoding error: invalid 
character in "%s" attribute;]')\
-          #      % (name, attr)
-          #  raise MarkupError, tmsg
-
-          #except StandardError, msg:
-          #  raise
-          #  tmsg = _('Error processing <%s> tag [invalid type for "%s" 
attribute; value is "%s"]')\
-          #      % (name, attr, saxattrs[qattr])
-          #  raise MarkupError, tmsg
-
           # If this attribute must be unique, check for duplicates
-          if baseAttrs[attr].get('Unique',0): # default 
(baseAttrs[attr],'Unique',0):
-            if self.uniqueIDs.has_key('%s' % (saxattrs[qattr])):
+          if baseAttrs [attr].get ('Unique', False):
+            if self.uniqueIDs.has_key ('%s' % (saxattrs [qattr])):
               tmsg = u_('Error processing <%(tag)s> tag ["%(attribute)s" '
                         'attribute should be unique; duplicate value is '
                         '"%(duplicate)s"]') \
@@ -380,65 +399,64 @@
                         'duplicate': saxattrs [qattr]}
               raise MarkupError, (tmsg, self.url, self.parser.getLineNumber ())
 
-            # FIXME: If we really want to have a working 'Unique'-Attribute, we
-            # would add the following line. But this would break forms atm.
-            # self.uniqueIDs ["%s" % saxattrs [qattr]] = True
+            self.uniqueIDs ["%s" % saxattrs [qattr]] = True
 
 
-      for attr in baseAttrs.keys():
+      for attr in baseAttrs:
         try:
-          if not attrs.has_key(attr):
-  
+          if not attr in attrs:
             # Pull default values for missing attributes
-            if baseAttrs[attr].has_key ('Default'):
-              attrs[attr] = baseAttrs[attr].get('Typecast', GTypecast.text) 
(baseAttrs[attr]['Default'])
+            if 'Default' in baseAttrs [attr]:
+              typecast     = baseAttrs [attr].get ('Typecast', GTypecast.text)
+              attrs [attr] = typecast (baseAttrs [attr]['Default'])
   
             # Check for missing required attributes
-            elif baseAttrs[attr].get('Required', False): 
-              tmsg = u_('Error processing <%(tagname)s> tag [required 
attribute '
-                        '"%(attribute)s" not present]') \
-                    % {'tagname'  : name,
-                        'attribute': attr}
-              raise MarkupError, (tmsg, self.url, self.parser.getLineNumber ())
-        except (AttributeError, KeyError), msg: 
-          raise errors.SystemError, _( 
-            'Error in GParser xmlElement definition for %s/%s'
-                ) % (name, attr) + '\n' + str(msg)
+            elif baseAttrs [attr].get ('Required', False):
+              tm = u_('Error processing <%(tagname)s> tag [required attribute '
+                      '"%(attribute)s" not present]') \
+                   % {'tagname': name, 'attribute': attr}
+              raise MarkupError, (tm, self.url, self.parser.getLineNumber ())
 
-      attrs['_xmlnamespaces'] = xmlns
+        except (AttributeError, KeyError), msg:
+          raise errors.SystemError, \
+              u_("Error in GParser xmlElement definition for %(tag)s/%(attr)s"
+                 "\n%(message)s") \
+              % {'tag': name, 'attr': attr, 'message': msg}
 
+      attrs ['_xmlnamespaces'] = xmlns
+
       if self.bootstrapflag:
-        if self.xmlStack[0] != None:
-          object = self.xmlElements[name]['BaseClass'](self.xmlStack[0])
+        if self.xmlStack [0] is not None:
+          object = self.xmlElements [name]['BaseClass'] (self.xmlStack [0])
       else:
-        object = self.xmlElements[name]['BaseClass']()
+        object = self.xmlElements [name]['BaseClass'] ()
         self.root = object
         self.bootstrapflag = 1
 
       try:
-        self._tagCounts[name] += 1
+        self._tagCounts [name] += 1
+
       except KeyError:
         pass
 
-      object._xmltag = name
-      object._xmlnamespace = ns
-      object._listedAttributes = loadedxmlattrs.keys()
+      object._xmltag           = name
+      object._xmlnamespace     = ns
+      object._listedAttributes = loadedxmlattrs.keys ()
       
     elif self.xmlMasqueradeNamespaceElements:
       #
       # namespace qualifier and we are masquerading
       #
-
       assert gDebug (7, "<%s:%s>" % (ns,name))
 
-      for qattr in saxattrs.keys():
+      for qattr in saxattrs:
         attrns, attr = qattr
+        attrs [attr] = saxattrs [qattr]
+        loadedxmlattrs [attr] = saxattrs [qattr]
 
-        attrs[attr] = saxattrs[qattr]
-        loadedxmlattrs[attr] = saxattrs[qattr]
+      try:
+        object = self.xmlMasqueradeNamespaceElements (self.xmlStack [0])
 
-      try:
-        object = self.xmlMasqueradeNamespaceElements(self.xmlStack[0])
       except IndexError:
         tmsg = u_("Error processing <%(namespace)s:%(name)s> tag: root "
                   "element needs to be in default namespace") \
@@ -446,277 +464,372 @@
                   'name'     : name}
         raise MarkupError, (tmsg, self.url, self.parser.getLineNumber ())
 
-      object._xmltag = name
-      object._xmlnamespace = ns
-      object._listedAttributes = loadedxmlattrs.keys()
+      object._xmltag           = name
+      object._xmlnamespace     = ns
+      object._listedAttributes = loadedxmlattrs.keys ()
 
     elif self.ignore_unknown_namespaces:
-      self.xmlStack.insert(0, None)
-      self.nameStack.insert(0, None)
+      self.xmlStack.insert (0, None)
+      self.nameStack.insert (0, None)
+
       return
+
     else:
       #
       # namespace qualifier and we are not masquerading
       #
-      tmsg =  u_("WARNING: Markup includes unsupported namespace '%s'." ) % 
(ns)
+      tmsg = u_("WARNING: Markup includes unsupported namespace '%s'.") % ns
       raise MarkupError, (tmsg, self.url, self.parser.getLineNumber ())
 
 
-    # Save the attributes loaded from XML file
-    # (i.e., attributes that were not defaulted)
+    # Save the attributes loaded from XML file (i.e., attributes that were not
+    # defaulted)
     object._loadedxmlattrs = loadedxmlattrs
     
     # We make the url of the xml-stream and the line number of the element
     # available to the instance (for later error handling)
-    object._lineNumber     = self.parser.getLineNumber ()
-    object._url            = self.url
+    object._lineNumber = self.parser.getLineNumber ()
+    object._url        = self.url
 
     # Set the attributes
-    object.__dict__.update(attrs)
+    object.__dict__.update (attrs)
 
-    self.xmlStack.insert(0, object)
-    self.nameStack.insert(0, name)
+    self.xmlStack.insert (0, object)
+    self.nameStack.insert (0, name)
 
     # processing trigger/procedure code from external files
-    for qattr in saxattrs.keys():
+    for qattr in saxattrs.keys ():
       attrns, attr = qattr
 
       if baseAttrs.has_key ('file') and attr == 'file':
-        textEncoding=gConfig('textEncoding')
-        handle = openResource(attrs[attr])
-        text = handle.read().decode(textEncoding)
-        handle.close()
+        # FIXME: find a better way to handle encoding of external resources
+        textEncoding = gConfig('textEncoding')
+        handle = openResource (attrs [attr])
+        text = handle.read ().decode (textEncoding)
+        handle.close ()
         
-        if self.xmlStack[0] != None:
-          GContent(self.xmlStack[0], text)
+        if self.xmlStack [0] != None:
+          GContent (self.xmlStack [0], text)
 
 
-  #
-  # Called by the internal SAX parser whenever
-  # text (not part of a tag) is encountered.
-  #
-  def characters(self, text):
+
+
+  # ---------------------------------------------------------------------------
+  # Process text which is not part of a tag (=contents)
+  # ---------------------------------------------------------------------------
+
+  def characters (self, text):
+    """
+    Called by the internal SAX parser whenever text (not part of a tag) is
+    encountered.
+    """
  
-    if self.xmlStack[0] != None:
-
+    if self.xmlStack [0] != None:
       # Masqueraging namespace elements, then keep content
       xmlns = self.xmlMasqueradeNamespaceElements and \
-          isinstance(self.xmlStack[0],self.xmlMasqueradeNamespaceElements)
+          isinstance (self.xmlStack [0], self.xmlMasqueradeNamespaceElements)
 
       # Should we keep the text?
-      if xmlns or self.xmlElements[self.nameStack[0]].get('MixedContent',0):
-
+      if xmlns or self.xmlElements [self.nameStack [0]].get('MixedContent', 0):
         if xmlns or 
self.xmlElements[self.nameStack[0]].get('KeepWhitespace',0):
-          GContent(self.xmlStack[0], text)
+          GContent (self.xmlStack [0], text)
         else:
           # Normalize
-          if len(string.replace(string.replace(string.replace(text,' 
',''),'\n',''),'\t','')):
+          if len (text.strip ()):
             text = normalise_whitespace (text)
           else:
             text = ""
-          if len(text):
-            GContent(self.xmlStack[0], text)
 
+          if len (text):
+            GContent (self.xmlStack [0], text)
 
-  #
-  # Called by the internal SAX parser whenever
-  # an ending XML tag/element is encountered.
-  #
-  def endElementNS(self, qtag, qname):
+
+  # ---------------------------------------------------------------------------
+  # End of a XML tag encountered
+  # ---------------------------------------------------------------------------
+
+  def endElementNS (self, qtag, qname):
+    """
+    Called by the internal SAX parser whenever an ending XML tag/element is
+    encountered.
+    """
+
     ns, name = qtag
-    self.nameStack.pop(0)
-    child = self.xmlStack.pop(0)
+    self.nameStack.pop (0)
+    child = self.xmlStack.pop (0)
 
     if not child:
       return
 
-    inits = child._buildObject()
+    inits = child._buildObject ()
     self._phaseInitCount = (inits != None and inits > self._phaseInitCount \
                             and inits or self._phaseInitCount)
     assert gDebug (7, "</%s>" % name)
 
 
-  #  lexical handler stuff
-  def comment(self, text):
+  # ---------------------------------------------------------------------------
+  # Get the root comments sequence
+  # ---------------------------------------------------------------------------
+
+  def getRootComments (self):
+    """
+    @returns: sequence of comment tags given before the root node
+    """
+
+    return self._rootComments
+
+
+  # ---------------------------------------------------------------------------
+  # Lexical handler stuff
+  # ---------------------------------------------------------------------------
+
+  def comment (self, text):
+
     if self.root is None:
-      self._rootComments.append(text)
+      self._rootComments.append (text)
     else:
-      if self.xmlStack[0] != None:
-        GComment(self.xmlStack[0], text)
+      if self.xmlStack [0] != None:
+        GComment (self.xmlStack [0], text)
 
-  def startCDATA(self):
+  # ---------------------------------------------------------------------------
+
+  def startCDATA (self):
     pass
   
-  def endCDATA(self):
+  # ---------------------------------------------------------------------------
+
+  def endCDATA (self):
     pass
       
-  def startDTD(self, name, public_id, system_id):
+  # ---------------------------------------------------------------------------
+
+  def startDTD (self, name, public_id, system_id):
     pass
           
-  def endDTD(self):
+  # ---------------------------------------------------------------------------
+
+  def endDTD (self):
     pass
 
-  def startEntity(self, name):
+  # ---------------------------------------------------------------------------
+
+  def startEntity (self, name):
     pass
 
-  def endEntity(self, name):
+  # ---------------------------------------------------------------------------
+
+  def endEntity (self, name):
     pass
 
-  def getRootComments(self):
-    return self._rootComments
 
 
-class GImportItem(GObj):
-  def __init__(self, parent=None, type="GCImport-Item"):
-    GObj.__init__(self, parent, type=type)
+# =============================================================================
+# Base class for importable items
+# =============================================================================
+
+class GImportItem (GObj):
+  """
+  This class is used for loading importable items from external resources.
+  """
+
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, parent = None, type = "GCImport-Item"):
+
+    GObj.__init__ (self, parent, type = type)
+
     self._loadedxmlattrs = {} # Set by parser
-    self._inits = [self.primaryInit]
-    self._xmlParser = self.findParentOfType(None)._xmlParser
+    self._inits          = [self.__primaryInit]
+    self._xmlParser      = self.findParentOfType (None)._xmlParser
 
-  def _buildObject(self):
-    if hasattr(self,'_xmltag'):
+
+  # ---------------------------------------------------------------------------
+  # Prepare the type or the importclass for the object
+  # ---------------------------------------------------------------------------
+
+  def _buildObject (self):
+    """
+    After the parser has built the object determine either the apropriate type
+    or the importclass for the object. This will be needed by the phase-init.
+
+    @returns: number of phase initializations needed by this object
+    """
+
+    if hasattr (self, '_xmltag'):
       self._type = 'GC%s' % self._xmltag
-    if not hasattr(self,'_importclass'):
-      self._importclass = self._xmlParser\
-         .getXMLelements()[string.lower(self._type[9:])]['BaseClass']
-    return GObj._buildObject(self)
 
-  def primaryInit(self):
-     #
-     # Open the library and convert it into objects
-     #
-     handle = openResource(self.library)
-     parent = self.findParentOfType (None)
+    if not hasattr (self, '_importclass'):
+      item = self._type [9:].lower ()
+      self._importclass = self._xmlParser.getXMLelements () [item]['BaseClass']
 
-     # Let the parent provide it's instance either as _app or _instance
-     if hasattr (parent, '_instance'):
-       instance = parent._instance
-     elif hasattr (parent, '_app'):
-       instance = parent._app
-     else:
-       instance = None
+    return GObj._buildObject (self)
 
-     form = self._xmlParser.loadFile (handle, instance, initialize = 0)
-     handle.close ()
-     id = 'id'
-     if hasattr(self,'name'):
-         id = 'name'
-     #
-     # Configure the imported object, assign as a child of self
-     #
-     rv = self.__findImportItem(self, form, id)
-     if rv != None:
-       rv.setParent (self)
-       rv._IMPORTED = 1
-       self._children.append(rv)
-       #
-       # transfer attributes reassigned during the import
-       #
-       for key in self._loadedxmlattrs.keys():
-         if key[0] != '_':
-           rv.__dict__[key] = self._loadedxmlattrs[key]
-           assert gDebug (7, ">>> Moving %s" % key)
-       rv._buildObject()
-     else:
-         raise MarkupError, \
-             (u_("Unable to find an importable object named %(name)s in "
-                 "%(library)s") \
-              % {'name'   : self.name, 'library': self.library},
-              self.url)
 
-  #
-  # __findImportItem
-  #
-  # finds the item in the object tree with the
-  # same name and instance type
-  #
-  def __findImportItem(self, find, object, id):
-     if isinstance(object, find._importclass) and \
-        hasattr(object, id) and \
-        object.__dict__[id] == find.__dict__[id]:
+  # ---------------------------------------------------------------------------
+  # Phase I init
+  # ---------------------------------------------------------------------------
+
+  def __primaryInit (self):
+
+    # Open the library and convert it into objects
+    handle = openResource (self.library)
+    parent = self.findParentOfType (None)
+
+    # Let the parent provide it's instance either as _app or _instance
+    if hasattr (parent, '_instance'):
+      instance = parent._instance
+    elif hasattr (parent, '_app'):
+      instance = parent._app
+    else:
+      instance = None
+
+    form = self._xmlParser.loadFile (handle, instance, initialize = 0)
+    handle.close ()
+
+    id = hasattr (self, 'name') and 'name' or 'id'
+
+    # Configure the imported object, assign as a child of self
+    rv = self.__findImportItem (self, form, id)
+    if rv is not None:
+      rv._IMPORTED = True
+      rv.setParent (self)
+      self.addChild (rv)
+
+      # transfer attributes reassigned during the import
+      for key in [k for k in self._loadedxmlattrs.keys () if k [0] != '_']:
+        rv.__dict__ [key] = self._loadedxmlattrs [key]
+        assert gDebug (7, ">>> Moving %s" % key)
+
+      rv._buildObject ()
+
+    else:
+      raise MarkupError, \
+          (u_("Unable to find an importable object named %(name)s in "
+              "%(library)s") % {'name'   : self.name, 'library': self.library},
+           self.url)
+
+
+  # ---------------------------------------------------------------------------
+  # find an item of a given name and type
+  # ---------------------------------------------------------------------------
+
+  def __findImportItem (self, find, object, id):
+
+     if isinstance (object, find._importclass) and \
+        hasattr (object, id) and \
+        object.__dict__ [id] == find.__dict__ [id]:
        return object
-     elif hasattr(object,'_children'):
+
+     elif hasattr (object,'_children'):
        rv = None
        for child in object._children:
-         rv = self.__findImportItem(find, child, id)
+         rv = self.__findImportItem (find, child, id)
          if rv:
            break
+
        return rv
+
      else:
        return None
 
 
-class GImport(GObj):
-  def __init__(self, parent=None):
-    GObj.__init__(self, parent, type="GCImport")
-    self.library = ""
-    self._form = None
-    self._inits = [self.primaryInit]
-    self._xmlParser = self.findParentOfType(None)._xmlParser
+# =============================================================================
+# Generic class for importable objects 
+# =============================================================================
 
-  def primaryInit(self):
-    handle = openResource(self.library)
-    form = self._xmlParser.loadFile(handle, self.findParentOfType(None)._app, 
initialize=0)
-    handle.close()
+class GImport (GObj):
 
-    for attribute in self._loadedxmlattrs.keys():
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__(self, parent = None):
+
+    GObj.__init__ (self, parent, type = "GCImport")
+    self.library    = ""
+    self._form      = None
+    self._inits     = [self.__primaryInit]
+    self._xmlParser = self.findParentOfType (None)._xmlParser
+
+
+  # ---------------------------------------------------------------------------
+  # Phase I initialization
+  # ---------------------------------------------------------------------------
+
+  def __primaryInit (self):
+
+    handle = openResource (self.library)
+    form   = self._xmlParser.loadFile (handle,
+        self.findParentOfType (None)._app, initialize = False)
+    handle.close ()
+
+    for attribute in self._loadedxmlattrs.keys ():
       if attribute != 'library':
-        importAll =  self._loadedxmlattrs[attribute] == "*"
-        importNames = 
string.split(string.replace(self._loadedxmlattrs[attribute],' ',''),',')
+        attr        = self._loadedxmlattrs [attribute]
+        importAll   = attr == "*"
+        importNames = attr.replace (' ', '').split (',')
 
-        instanceType = 
self._xmlParser.getXMLelements()[string.lower(attribute)]['BaseClass']
+        elements     = self._xmlParser.getXMLelements ()
+        instanceType = elements [attribute.lower ()]['BaseClass']
 
-        if importAll or len(importNames):
+        if importAll or len (importNames):
           for child in form._children:
-            if isinstance(child,instanceType) and \
+            if isinstance (child, instanceType) and \
                (importAll or child.name in importNames):
               child.setParent (self)
               child._IMPORTED = 1
-              self._children.append(child)
-              child._buildObject()
+              self.addChild (child)
+              child._buildObject ()
 
-def buildImportableTags(rootTag, elements):
-    #
-    # Scans xml elements and looks for Importable = 1
-    # Items with this set can be imported
-    # If an object needs to be importable,
-    # simply add its tag name to the tuple below
-    # and make sure it has a "name" attribute
-    # (otherwise we don't know how to reference
-    # it in the imported file).
-    #
-    importElement = {'BaseClass': GImport,
-                     'Attributes': {'library': {
-                                      'Required': 1,
-                                      'Typecast': GTypecast.name },
-                                   },
-                     'ParentTags': rootTag,
-                     }
 
-    for key in elements.keys():
-     if elements[key].has_key('Importable') and elements[key]['Importable']:
-       name = "import-%s" % key
-       copy._deepcopy_dispatch[types.FunctionType] = copy._deepcopy_atomic
-       copy._deepcopy_dispatch[types.ClassType] = copy._deepcopy_atomic
-       copy._deepcopy_dispatch[type(int)] = copy._deepcopy_atomic
+# -----------------------------------------------------------------------------
+# build importable tags
+# -----------------------------------------------------------------------------
 
-       p = copy.deepcopy(elements[key])
-       p['BaseClass'] = GImportItem
+def buildImportableTags (rootTag, elements):
+  """
+  Scans XML elements and looks for 'Importable' items. If an object needs to be
+  importable, simply add its tag name to the tuple below and make sure it has a
+  "name" attribute (otherwise we don't know how to reference it in the imported
+  file).
+  """
 
-       if not p.has_key('Attributes'):
-         p['Attributes'] = {}
+  importElement = {'BaseClass' : GImport,
+                   'Attributes': {'library': {
+                                    'Required': True,
+                                    'Typecast': GTypecast.name},
+                                 },
+                   'ParentTags': rootTag,
+                  }
 
-       p['Attributes']['library'] = {
-          'Required': 1,
+  for key in elements.keys ():
+    if elements [key].get ('Importable', False):
+      name = "import-%s" % key
+
+      copy._deepcopy_dispatch [types.FunctionType] = copy._deepcopy_atomic
+      copy._deepcopy_dispatch [types.ClassType] = copy._deepcopy_atomic
+      copy._deepcopy_dispatch [type (int)] = copy._deepcopy_atomic
+
+      p = copy.deepcopy (elements [key])
+      p ['BaseClass'] = GImportItem
+
+      if not p.has_key ('Attributes'):
+        p ['Attributes'] = {}
+
+      p ['Attributes']['library'] = {
+          'Required': True,
           'Typecast': GTypecast.name }
-       p['MixedContent'] = 0
-       p['Required'] = 0
-       elements[name] = p
+      p ['MixedContent'] = False
+      p ['Required'] = False
 
-       importElement['Attributes'][key] =  {
-         'Typecast': GTypecast.name,
-         'Default': ""  }
+      elements [name] = p
 
-    if len(importElement['Attributes'].keys()):
-      elements['import'] = importElement
-    return elements
+      importElement ['Attributes'][key] = {'Typecast': GTypecast.name,
+                                           'Default' : ""}
+
+  if importElement ['Attributes']:
+    elements ['import'] = importElement
+
+  return elements

Modified: trunk/gnue-common/src/definitions/GParserHelpers.py
===================================================================
--- trunk/gnue-common/src/definitions/GParserHelpers.py 2005-11-11 18:27:31 UTC 
(rev 8095)
+++ trunk/gnue-common/src/definitions/GParserHelpers.py 2005-11-15 13:35:43 UTC 
(rev 8096)
@@ -21,15 +21,35 @@
 #
 # $Id$
 
+"""
+Base classes for GNUe objects which can be represented as XML.
+"""
+
 from xml.sax import saxutils
-from types import StringType
+from gnue.common.apps import errors
 
+__all__ = ['ParserObj', 'GLeafNode', 'GContent', 'GComment']
 
+
 # =============================================================================
+# Exceptions
+# =============================================================================
+
+class AssignmentTypeError (errors.ApplicationError):
+  def __init__ (self, dst, source):
+    msg = u_("Cannot assign class '%(source)s' to class '%(dest)s'") \
+          % {'source': source.__class__, 'dest': dst.__class__}
+    errors.ApplicationError.__init__ (self, msg)
+
+
+# =============================================================================
 # Base class for GParser objects
 # =============================================================================
 
 class ParserObj:
+  """
+  Base class for objects handled by a L{gnue.common.definitions.GParser}.
+  """
 
   # ---------------------------------------------------------------------------
   # Constructor
@@ -58,7 +78,7 @@
     """
     Returns the immediate parent of an object instance in a GObj tree.
 
-    @return: The parent of the object in the GObj tree.
+    @returns: The parent of the object in the GObj tree.
     @rtype: any
     """
 
@@ -80,35 +100,36 @@
 
 
   # ---------------------------------------------------------------------------
-  # Return a compareable id of an object
+  # add an object to the list of children
   # ---------------------------------------------------------------------------
 
-  def _id_ (self, maxIdLength = None):
+  def addChild (self, child):
     """
-    Return a compareable and identifying id of an object within a tree. Usually
-    this is it's name (if available) or it's object type (as given in the
-    constructor).
+    Add an object to the list of children
 
-    @param maxIdLength: if not None only return up to maxIdLength characters.
-    @return: id for the instance
+    @param child: The object to add.
+    @type child: L{ParserObj} derived class
     """
 
-    if hasattr (self, 'name'):
-      result = self.name.lower ()
-      if maxIdLength is not None:
-        result = result [:maxIdLength]
-    else:
-      result = self._type
+    self._children.append (child)
 
-    return result
 
-
   # ---------------------------------------------------------------------------
   # Assign a given set of attributes from another instance
   # ---------------------------------------------------------------------------
 
   def assign (self, source, recursive = False):
     """
+    Assign all attributes from a given object to this one. If the recursive
+    option is given, all of the source's children will be I{duplicated} and
+    assigned to this object.
+
+    @param source: the L{ParserObj} instance to assign attributes from
+    @param recursive: if True, all children of source will be recursiveley
+      duplicated and assigned to this object
+
+    @raises AssignmentTypeError: if the source object is another class than
+      this object
     """
 
     if self.__class__ != source.__class__:
@@ -139,6 +160,8 @@
   def merge (self, other, maxIdLength = None):
     """
     Incorporate all subtrees from the given object tree of this instances type.
+
+    @param other: L{ParserObj} tree to be merged into this object tree
     """
 
     # First find objects of the same type in the other tree
@@ -168,6 +191,18 @@
 
   def diff (self, goal, maxIdLength = None):
     """
+    Build an object tree representing the difference between two object trees.
+
+    @param goal: L{ParserObj} tree to compare this object's tree to.
+    @param maxIdLength: if defined, use only up to maxIdLength characters of
+      the object name to check for identity.
+    @returns: L{ParserObj} tree representing the difference. Every object in
+      this tree has an additional attribute B{_action} which can contain one of
+      the following values:
+
+      * add: the object is only available in the 'goal' tree
+      * change: the object is avaialable in both trees, but differs
+      * remove: the object is only available in the 'source' tree
     """
 
     result = None
@@ -231,14 +266,273 @@
 
 
   # ---------------------------------------------------------------------------
-  # Set the diff-action for a given object
+  # Return a XML representation of the object
   # ---------------------------------------------------------------------------
 
+  def dumpXML (self, lookupDict, treeDump = False, gap = "  ",
+      xmlnamespaces = {}, textEncoding = '<locale>', stripPrefixes = None,
+      escape = True):
+    """
+    Return a XML representation of the object.
+
+    @param lookupDict: dictionary describing the XML entities, their
+      attributes and types
+    @param treeDump: if True, also include a XML representation of all 
children 
+    @param gap: string defining the current indentation level
+    @param xmlnamespaces: dictionary with the available XML namespaces
+    @param textEncoding: encoding used to transform string-type attributes into
+      unicode. If textEncoding is set to '<locale>' (default) it will be set to
+      the configuration variable 'textEncoding', i.e. from gnue.conf
+    @param stripPrefixes: a list of prefixes that will automatically be removed
+      from the objects type.  This can be used to remove the GF from the start
+      of all the gnue-forms objects.  If set to None (the default) then the
+      behaviour will be the old style which removes the first two characters
+      from the type.
+    @param escape: if set to True the resulting XML string should be escaped
+
+    @returns: a string with the object's XML representation
+    """
+
+    return self._dumpXML_ (lookupDict, treeDump, gap, xmlnamespaces,
+        textEncoding, stripPrefixes, escape)
+
+
+  # ---------------------------------------------------------------------------
+  # Find the first parent instance of a given type
+  # ---------------------------------------------------------------------------
+
+  def findParentOfType (self, parentType, includeSelf = True):
+    """
+    Moves upward though the parents of an object till it finds the parent of
+    the specified type.
+
+    @param parentType: type of the object to be found
+    @param includeSelf: if set to True, the search starts with this object
+      instead of the object's parent.
+
+    @returns: the first parent object of the given type or None if no such
+      object was found.
+    """
+
+    parentObject = includeSelf and self or self.__parent
+
+    while True:
+      if parentObject is None:
+        return None
+
+      elif parentObject._type == parentType:
+        return parentObject
+
+      # If passed a type of NONE it finds the top object in the tree
+      if not parentType and not parentObject.__parent:
+        return parentObject
+
+      parentObject = parentObject.__parent
+
+
+  # ---------------------------------------------------------------------------
+  # Find the first child object with a given name and type
+  # ---------------------------------------------------------------------------
+
+  def findChildNamed (self, name, childType = None):
+    """
+    Moves downward though the children of an object till it finds the child
+    with the specified name.
+
+    @param name: The name to search for
+    @param childType: The type of object to search for, if None then any type
+      will match.
+
+    @return: The child with the matching name, or None if child not found
+    """
+
+    for child in self._children:
+      if child.name == name:
+        if childType is None or child._type == childType:
+          return child
+
+    return None
+
+
+  # ---------------------------------------------------------------------------
+  # Find the first child of a given type
+  # ---------------------------------------------------------------------------
+
+  def findChildOfType (self, childType, includeSelf = True,
+      allowAllChildren = False):
+    """
+    Moves downward through the children of an object till it finds the child of
+    the specified type.
+
+    @param childType: type of the child to be searched for
+    @param includeSelf: if set to True, the search starts with this instance
+    @param allowAllChildren: if set to True, the search will be performed
+      recursive.
+
+    @returns: the first child of the requested type or None if no such object
+      is found.
+    """
+
+    if includeSelf and self._type == childType:
+      return self
+
+    for child in self._children:
+      if child._type == childType:
+        return child
+
+    if allowAllChildren:
+      for child in self._children:
+        o = child.findChildOfType (childType, False, True)
+        if o:
+          return o
+
+    return None
+
+
+  # ---------------------------------------------------------------------------
+  # Find children of a given type
+  # ---------------------------------------------------------------------------
+
+  def findChildrenOfType (self, childType, includeSelf = True,
+      allowAllChildren = False):
+    """
+    Find all children of a specific type.
+
+    @param childType: type of the objects to match
+    @param includeSelf: if set to True, the search will be started with this
+      instance.
+    @param allowAllChildren: if set to True, recursivley step down the object
+      tree and add all children of the requested type
+
+    @returns: sequence with all child objects matching the requested type
+    """
+
+    result = []
+    add    = result.append
+    extend = result.extend
+
+    if includeSelf and self._type == childType:
+      add (self)
+
+    for child in self._children:
+      if child._type == childType:
+        add (child)
+
+    if allowAllChildren:
+      for child in self._children:
+        extend (child.findChildrenOfType (childType, False, True))
+
+    return result
+
+
+  # ---------------------------------------------------------------------------
+  # Get a description for an object
+  # ---------------------------------------------------------------------------
+
+  def getDescription (self):
+    """
+    Return a useful description of the object. Currently used by GNUe Designer.
+    """
+
+    if hasattr (self, '_description'):
+      return self._description
+
+    elif hasattr (self, 'name'):
+      return "%s (%s)" % (self.name, self._type [2:])
+
+    else:
+      return "%s (%s)" % (self._type [2:], self._type [2:])
+
+
+  # ---------------------------------------------------------------------------
+  # Get the contents of all children of type GContent
+  # ---------------------------------------------------------------------------
+
+  def getChildrenAsContent (self):
+    """
+    Returns the content of any GContent objects that are children of this
+    object.
+
+    @returns: The contents of the children
+    """
+
+    result = ""
+
+    for child in self._children:
+      if isinstance (child, GContent):
+        result += child._content
+
+      elif isinstance (child, GBinary):
+        result += child.__data__
+
+    return result
+
+
+  # ===========================================================================
+  # Virtual functions
+  # ===========================================================================
+
+  def _id_ (self, maxIdLength = None):
+    """
+    Return a compareable and identifying id of an object within a tree. Usually
+    this is it's name (if available) or it's object type (as given in the
+    constructor).
+
+    @param maxIdLength: if not None only return up to maxIdLength characters.
+    @return: id for the instance
+    """
+
+    if hasattr (self, 'name'):
+      result = self.name.lower ()
+      if maxIdLength is not None:
+        result = result [:maxIdLength]
+    else:
+      result = self._type
+
+    return result
+
+
+  # ---------------------------------------------------------------------------
+
   def _diffActionWalker_ (self, obj, action):
+    """
+    Set the action attribute of a given object to the specified action.
 
+    @param obj: L{ParserObj} to set the action attribute
+    @param action: the action to be set
+    """
+
     obj._action = action
 
 
+  # ---------------------------------------------------------------------------
+
+  def _dumpXML_ (self, lookupDict, treeDump, gap, xmlnamespaces, textEncoding,
+      stripPrefixes, escape):
+    """
+    Return a XML representation of the object.
+
+    @param lookupDict: dictionary describing the XML entities, their
+      attributes and types
+    @param treeDump: if True, also include a XML representation of all 
children 
+    @param gap: string defining the current indentation level
+    @param xmlnamespaces: dictionary with the available XML namespaces
+    @param textEncoding: encoding used to transform string-type attributes into
+      unicode. If textEncoding is set to '<locale>' (default) it will be set to
+      the configuration variable 'textEncoding', i.e. from gnue.conf
+    @param stripPrefixes: a list of prefixes that will automatically be removed
+      from the objects type.  This can be used to remove the GF from the start
+      of all the gnue-forms objects.  If set to None (the default) then the
+      behaviour will be the old style which removes the first two characters
+      from the type.
+    @param escape: if set to True the resulting XML string should be escaped
+
+    @returns: a string with the object's XML representation
+    """
+
+    raise NotImplementedError
+
+
 # =============================================================================
 # Mixin-class for leaf node objects
 # =============================================================================
@@ -263,6 +557,9 @@
 # =============================================================================
 
 class GContent (ParserObj):
+  """
+  Class representing XML content.
+  """
 
   # ---------------------------------------------------------------------------
   # Constructor
@@ -271,7 +568,8 @@
   def __init__ (self, parent, content = None):
 
     ParserObj.__init__ (self, parent, '_content_')
-    self._content = content
+    self._content     = content
+    self._description = "(Content)"
 
 
   # ---------------------------------------------------------------------------
@@ -279,6 +577,9 @@
   # ---------------------------------------------------------------------------
 
   def getEscapedContent (self):
+    """
+    @returns: The escaped contents of this object
+    """
 
     return saxutils.escape (self._content)
 
@@ -288,53 +589,62 @@
   # ---------------------------------------------------------------------------
 
   def getContent (self):
+    """
+    @returns: The contents of this object
+    """
 
     return self._content
 
 
   # ---------------------------------------------------------------------------
-  # Return a xml representation of the object
+  # Show a contents element within an (indented) tree
   # ---------------------------------------------------------------------------
 
-  def dumpXML (self, lookupDict, treeDump = None, gap = None,
-               escape = 1, textEncoding = '<locale>', xmlnamespaces = {},
-               stripPrefixes = None):
+  def showTree (self, indent = 0):
+    """
+    Show a contents element within an indented tree
+    """
 
-    if textEncoding == '<locale>':
-      textEncoding = gConfig ('textEncoding')
+    print ' ' * indent + 'GContent ' + `self._content`
 
-    if type (self._content) == StringType:
-      xmlString = '%s' % unicode (self._content, textEncoding)
-    else:
-      xmlString = self._content
 
-    return escape and saxutils.escape (xmlString) or xmlString
-
-
   # ---------------------------------------------------------------------------
-  # Show a contents element within an (indented) tree
+  # Don't merge contents instances
   # ---------------------------------------------------------------------------
 
-  def showTree (self, indent = 0):
+  def merge (self, other):
+    """
+    Content objects cannot be merged together
+    """
 
-    print ' ' * indent + 'GContent ' + `self._content`
+    return
 
 
   # ---------------------------------------------------------------------------
-  # Return a useful description of this object (used by designer clients)
+  # Implementation of virtual methods
   # ---------------------------------------------------------------------------
 
-  def getDescription (self):
+  def _dumpXML_ (self, lookupDict, treeDump, gap, xmlnamespaces, textEncoding,
+      stripPrefixes, escape):
+    """
+    Return a XML representation of the contents. If the contents is a plain
+    string (non unicode) it will be converted into unicode using the specified
+    encoding or (if set to '<locale>') using the encoding as defined by the
+    configuration variable 'textEncoding'. If the contents is of any other
+    type it will be returned as is.
 
-    return "(Content)"
+    @returns: XML representation of the contents
+    """
 
+    if textEncoding == '<locale>':
+      textEncoding = gConfig ('textEncoding')
 
-  # ---------------------------------------------------------------------------
-  # Don't merge contents instances
-  # ---------------------------------------------------------------------------
+    if isinstance (self._content, str):
+      xmlString = '%s' % unicode (self._content, textEncoding)
+    else:
+      xmlString = self._content
 
-  def merge (self, other):
-    return
+    return escape and saxutils.escape (xmlString) or xmlString
 
 
 # =============================================================================
@@ -342,6 +652,9 @@
 # =============================================================================
 
 class GComment (ParserObj):
+  """
+  Class representing a comment within a XML tree.
+  """
 
   # ---------------------------------------------------------------------------
   # Constructor
@@ -352,14 +665,27 @@
     ParserObj.__init__ (self, parent, '_comment_')
     self._comment = comment
 
-  def dumpXML (self, lookupDict, treeDump = None, gap = "",
-               escape = 1, textEncoding = '<locale>', xmlnamespaces = {},
-               stripPrefixes = None):
 
+  # ---------------------------------------------------------------------------
+  # Implementation of virtual methods
+  # ---------------------------------------------------------------------------
+
+  def _dumpXML_ (self, lookupDict, treeDump, gap, xmlnamespaces, textEncoding,
+      stripPrefixes, escape):
+    """
+    Return a XML representation of the comment. If the comment is a plain
+    string (non unicode) it will be converted into unicode using the specified
+    encoding or (if set to '<locale>') using the encoding as defined by the
+    configuration variable 'textEncoding'. If the comment is of any other
+    type it will be returned as is.
+
+    @returns: XML representation of the contents
+    """
+
     if textEncoding == '<locale>':
       textEncoding = gConfig ('textEncoding')
 
-    if type (self._comment) == StringType:
+    if isinstance (self._comment, str):
       xmlString = '%s' % unicode (self._comment, textEncoding)
     else:
       xmlString = self._comment

Modified: trunk/gnue-common/src/definitions/GRootObj.py
===================================================================
--- trunk/gnue-common/src/definitions/GRootObj.py       2005-11-11 18:27:31 UTC 
(rev 8095)
+++ trunk/gnue-common/src/definitions/GRootObj.py       2005-11-15 13:35:43 UTC 
(rev 8096)
@@ -1,65 +1,88 @@
+# GNU Enterprise Common Library - GNUe XML object definitions - Root Node
 #
-# This file is part of GNU Enterprise.
+# Copyright 2001-2005 Free Software Foundation
 #
-# GNU Enterprise is free software; you can redistribute it 
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise is free software; you can redistribute it
 # and/or modify it under the terms of the GNU General Public
-# License as published by the Free Software Foundation; either 
+# License as published by the Free Software Foundation; either
 # version 2, or (at your option) any later version.
 #
 # GNU Enterprise is distributed in the hope that it will be
-# useful, but WITHOUT ANY WARRANTY; without even the implied 
-# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 # PURPOSE. See the GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public 
+# You should have received a copy of the GNU General Public
 # License along with program; see the file COPYING. If not,
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# Copyright 2000-2005 Free Software Foundation
-#
-#
-# FILE:
-# GRootObj.py
-#
-# DESCRIPTION:
-# Provides the base class that can optionally be used by root objects
-# in a GObj based tree.
-#
-# NOTES:
-#
+# $Id$
 
+"""
+Provides the base class that can optionally be used by root objects in a GObj
+based tree.
+"""
 
+__all__ = ['GRootObj']
+
 from gnue.common.logic.NamespaceCore import GObjNamespace
 from gnue.common.definitions.GObjects import GObj
-#
+from gnue.common.utils.FileUtils import dyn_import
+
+# =============================================================================
 # GRootObj
-#
-#
-class GRootObj(GObj):
-  def __init__(self, rootName, xmlElementCallback, xmlParser, *args, **parms):
-    GObj.__init__(self,*args, **parms)
+# =============================================================================
+
+class GRootObj (GObj):
+
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, rootName, xmlElementCallback, xmlParser, *args, **parms):
+
+    GObj.__init__ (self, *args, **parms)
+
     self._triggerNamespaceTree = None
-    self._rname = rootName
-    self.__xmlElementCallback = xmlElementCallback
-    self._xmlParser = xmlParser
-    self._xmlnamespaces = {}
-    self._standardnamespaces = {}
-    self._rootComments = []
+    self._rname                = rootName
+
+    if isinstance (xmlParser, basestring):
+      self._xmlParser = dyn_import (xmlParser)
+    else:
+      self._xmlParser = xmlParser
+
+    self._xmlnamespaces        = {}
+    self._standardnamespaces   = {}
+    self._rootComments         = []
     
     # This will store any "global myVar" that the triggers execute.
     self._globalRuntimeNamespace = {}
 
-  def initTriggerSystem(self):
-    self._triggerNamespaceTree = GObjNamespace(self,rootName=self._rname)
+    self.__xmlElementCallback  = xmlElementCallback
 
-  def dumpXML(self, lookupDict={}, treeDump=1, gap="  ", xmlnamespaces={},\
-              textEncoding='<locale>', stripPrefixes=None):
-    xmlElements = lookupDict
-    xmlElements.update(self.__xmlElementCallback())
-    return GObj.dumpXML(self, xmlElements, \
-          treeDump, gap, xmlnamespaces=self._standardnamespaces, \
-          textEncoding=textEncoding, stripPrefixes=stripPrefixes)
 
+  # ---------------------------------------------------------------------------
+  # Initialize the trigger system
+  # ---------------------------------------------------------------------------
 
+  def initTriggerSystem (self):
 
+    self._triggerNamespaceTree = GObjNamespace (self, rootName = self._rname)
+
+
+  # ---------------------------------------------------------------------------
+  # Get the object's XML code tree
+  # ---------------------------------------------------------------------------
+
+  def dumpXML (self, lookupDict = {}, treeDump = True, gap = "  ",
+      xmlnamespaces= {}, textEncoding = '<locale>', stripPrefixes = None):
+
+    xmlElements = lookupDict
+    xmlElements.update (self.__xmlElementCallback ())
+
+    return GObj.dumpXML (self, xmlElements, treeDump, gap,
+        xmlnamespaces = self._standardnamespaces, textEncoding = textEncoding,
+        stripPrefixes = stripPrefixes)


Property changes on: trunk/gnue-common/src/definitions/GRootObj.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: trunk/gnue-common/src/definitions/__init__.py
===================================================================
--- trunk/gnue-common/src/definitions/__init__.py       2005-11-11 18:27:31 UTC 
(rev 8095)
+++ trunk/gnue-common/src/definitions/__init__.py       2005-11-15 13:35:43 UTC 
(rev 8096)
@@ -0,0 +1,26 @@
+# GNU Enterprise Common Library - GNUe XML object definitions
+#
+# Copyright 2001-2005 Free Software Foundation
+#
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+
+"""
+GNUe object trees based on XML.
+"""


Property changes on: trunk/gnue-common/src/definitions/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: trunk/gnue-common/src/logic/GTrigger.py
===================================================================
--- trunk/gnue-common/src/logic/GTrigger.py     2005-11-11 18:27:31 UTC (rev 
8095)
+++ trunk/gnue-common/src/logic/GTrigger.py     2005-11-15 13:35:43 UTC (rev 
8096)
@@ -184,21 +184,22 @@
     else:
       return string.upper(self.type)
 
-  #
-  # dumpXML
-  #
-  #
-  def dumpXML(self, lookupDict, treeDump=None, gap=None, xmlnamespaces={},
-              textEncoding='<locale>', stripPrefixes=None):
+
+  # ---------------------------------------------------------------------------
+  # Dump a XML representation of a trigger
+  # ---------------------------------------------------------------------------
+
+  def _dumpXML_ (self, lookupDict, treeDump, gap, xmlnamespaces, textEncoding,
+            stripPrefixes, escape):
     """
     Dumps an XML representation of a trigger.
-    used in saving.
     """
 
     try:
-      escape = not gConfig('StoreTriggersAsCDATA')
+      asCData = not gConfig ('StoreTriggersAsCDATA')
+
     except:
-      escape = False
+      asCData = False
 
     xmlEntity = "trigger"
     xmlString = "%s<%s" % (gap[:-2],xmlEntity)
@@ -244,12 +245,13 @@
         xmlString += ">\n"
 
       if treeDump:
-        if hasContent and not escape:
+        if hasContent and not asCData:
           xmlString += "<![CDATA["
         for child in self._children:
-          xmlString += child.dumpXML(lookupDict, 1,gap+"  ",escape=escape,
-              stripPrefixes = stripPrefixes)
-        if hasContent and not escape:
+          xmlString += child.dumpXML (lookupDict, True , gap + "  ",
+              xmlnamespaces, textEncoding, stripPrefixes, escape)
+
+        if hasContent and not asCData:
           xmlString += "]]>"
 
       if hasContent:





reply via email to

[Prev in Thread] Current Thread [Next in Thread]