def compound_object(element_name, attrnames, warn=False):
    """return a class which delegates bracket access to an internal dict.
       Missing attributes are delegated to the child dict for convenience.
       @note: Care must be taken when child nodes and attributes have the same names"""
    class CompoundObject():
        _original_fields = sorted(attrnames)
        _fields = [_prefix_keyword(a, warn) for a in _original_fields]

        def __init__(self, values, child_dict):
            for name, val in zip(self._fields, values):
                self.__dict__[name] = val
            self._child_dict = child_dict
            self.name = element_name

        def getAttributes(self):
            return [(k, getattr(self, k)) for k in self._fields]

        def hasAttribute(self, name):
            return name in self._fields

        def setAttribute(self, name, value):
            if name not in self._fields:
                self._original_fields.append(name)
                self._fields.append(_prefix_keyword(name, warn))
            self.__dict__[name] = value

        def hasChild(self, name):
            return name in self._child_dict

        def getChild(self, name):
            return self._child_dict[name]

        def addChild(self, name, attrs=None):
            if attrs is None:
                attrs = {}
            clazz = compound_object(name, attrs.keys())
            child = clazz([attrs.get(a) for a in sorted(attrs.keys())], _NO_CHILDREN)
            if len(self._child_dict) == 0:
                self._child_dict = OrderedDict()
            self._child_dict.setdefault(name, []).append(child)
            return child

        def __getattr__(self, name):
            if name[:2] != "__":
                return self._child_dict.get(name, None)
            raise AttributeError

        def __setattr__(self, name, value):
            if name != "_child_dict" and name in self._child_dict:
                self._child_dict[name] = value
            else:
                self.__dict__[name] = value

        def __delattr__(self, name):
            if name in self._child_dict:
                del self._child_dict[name]
            else:
                if name in self.__dict__:
                    del self.__dict__[name]
                self._original_fields.remove(name)
                self._fields.remove(_prefix_keyword(name, False))

        def __getitem__(self, name):
            return self._child_dict[name]

        def __str__(self):
            return "<%s,child_dict=%s>" % (self.getAttributes(), dict(self._child_dict))

        def toXML(self, initialIndent="", indent="    "):
            fields = ['%s="%s"' % (self._original_fields[i], str(getattr(self, k)))
                      for i, k in enumerate(self._fields) if getattr(self, k) is not None 
                      # see #3454
                      and not '{' in self._original_fields[i]]
            if not self._child_dict:
                return "%s<%s %s/>\n" % (initialIndent, element_name, " ".join(fields))
            else:
                s = "%s<%s %s>\n" % (
                    initialIndent, element_name, " ".join(fields))
                for l in self._child_dict.values():
                    for c in l:
                        s += c.toXML(initialIndent + indent)
                return s + "%s</%s>\n" % (initialIndent, element_name)

        def __repr__(self):
            return str(self)

    return CompoundObject
return a class which delegates bracket access to an internal dict.
       Missing attributes are delegated to the child dict for convenience.
       @note: Care must be taken when child nodes and attributes have the same names