diff options
author | jortel <devnull@localhost> | 2009-01-16 20:23:56 +0000 |
---|---|---|
committer | jortel <devnull@localhost> | 2009-01-16 20:23:56 +0000 |
commit | cf7a832de9a6ab3cbc302d025af432e906476d52 (patch) | |
tree | 078b3ab38c8d6d0689f088d15c1d99a8bfa1f160 /suds | |
parent | 9bfd3bd2308962c73a1280be14aded40845ba40c (diff) | |
download | suds-cf7a832de9a6ab3cbc302d025af432e906476d52.tar.gz |
Refactored xsd package: The schema object simplified to hold all children in (rawchildren); removed all flattening, since the tree is no longer re-arraned, all node copying has been removed :-). this will greatly improve performance in schemas with lots of references. flattening replaced by on-demaind approach using an iterator to provide a flattened view; redesigned dereferencing of @ref/@base using dependency sorted list. This ensures that all elements in the schema are dereferenced and in the correct order.
Diffstat (limited to 'suds')
-rw-r--r-- | suds/__init__.py | 2 | ||||
-rw-r--r-- | suds/bindings/document.py | 4 | ||||
-rw-r--r-- | suds/builder.py | 11 | ||||
-rw-r--r-- | suds/client.py | 5 | ||||
-rw-r--r-- | suds/servicedefinition.py | 5 | ||||
-rw-r--r-- | suds/xsd/__init__.py | 13 | ||||
-rw-r--r-- | suds/xsd/deplist.py | 126 | ||||
-rw-r--r-- | suds/xsd/schema.py | 35 | ||||
-rw-r--r-- | suds/xsd/sxbase.py | 341 | ||||
-rw-r--r-- | suds/xsd/sxbasic.py | 328 |
10 files changed, 538 insertions, 332 deletions
diff --git a/suds/__init__.py b/suds/__init__.py index 1e4554d..b6dbc53 100644 --- a/suds/__init__.py +++ b/suds/__init__.py @@ -29,7 +29,7 @@ import socket # Project properties # -properties = dict(version='0.3.4', build="(beta) R427-20090113") +properties = dict(version='0.3.4', build="(beta) R428-20090116") # # Exceptions diff --git a/suds/bindings/document.py b/suds/bindings/document.py index 3b42146..2119181 100644 --- a/suds/bindings/document.py +++ b/suds/bindings/document.py @@ -105,7 +105,7 @@ class Document(Binding): result = [] for p in pts: resolved = p[1].resolve() - for c in resolved.children: + for c in resolved: result.append((c.name, c)) return result @@ -120,7 +120,7 @@ class Document(Binding): result = [] for pt in self.part_types(method, input=False): pt = pt.resolve(nobuiltin=True) - for rt in pt.children: + for rt in pt: result.append(rt) break return result
\ No newline at end of file diff --git a/suds/builder.py b/suds/builder.py index 1e6f2ce..da8b257 100644 --- a/suds/builder.py +++ b/suds/builder.py @@ -53,7 +53,7 @@ class Builder: md.__type__ = type history = [] self.add_attributes(data, type) - for c in type.children: + for c in [c for c in type if not c.isattr()]: if self.skip_child(c): continue self.process(data, c, history) @@ -63,6 +63,8 @@ class Builder: """ process the specified type then process its children """ if type in history: return + if type.enum(): + return history.append(type) resolved = type.resolve() self.add_attributes(data, type) @@ -70,8 +72,7 @@ class Builder: if type.unbounded(): value = [] else: - children = resolved.children - if len(children) > 0: + if len(resolved) > 0: value = Factory.object(type.name) md = value.__metadata__ md.__type__ = type @@ -79,14 +80,14 @@ class Builder: if value is not None: data = value if not isinstance(data, list): - for c in resolved.children: + for c in resolved.children(): if self.skip_child(c): continue self.process(data, c, history) def add_attributes(self, data, type): """ add required attributes """ - for a in type.attributes: + for a in type.attributes(): name = '_%s' % a.name value = a.get_default() setattr(data, name, value) diff --git a/suds/client.py b/suds/client.py index 467d145..e6787de 100644 --- a/suds/client.py +++ b/suds/client.py @@ -195,9 +195,8 @@ class Factory: raise TypeNotFound(name) if type.enum(): result = InstFactory.object(name) - for e in type.children: - enum = e.name - setattr(result, enum, enum) + for e in type.children(): + setattr(result, e.name, e.name) else: try: result = self.builder.build(type) diff --git a/suds/servicedefinition.py b/suds/servicedefinition.py index a4e4e17..721c9c8 100644 --- a/suds/servicedefinition.py +++ b/suds/servicedefinition.py @@ -218,7 +218,10 @@ class ServiceDefinition: sig.append(p[0]) sig.append(', ') sig.append(')') - s.append(''.join(sig)) + try: + s.append(''.join(sig)) + except: + pass s.append(indent(3)) s.append('Types (%d):' % len(self.types)) for t in self.types: diff --git a/suds/xsd/__init__.py b/suds/xsd/__init__.py index 0e55563..0917f3f 100644 --- a/suds/xsd/__init__.py +++ b/suds/xsd/__init__.py @@ -71,3 +71,16 @@ def isqref(object): len(object) == 2 and \ isinstance(object[0], basestring) and \ isinstance(object[1], basestring)) + + +class Filter: + def __init__(self, inclusive=False, *items): + self.inclusive = inclusive + self.items = items + def __contains__(self, x): + if self.inclusive: + result = ( x in self.items ) + else: + result = ( x not in self.items ) + return result + diff --git a/suds/xsd/deplist.py b/suds/xsd/deplist.py new file mode 100644 index 0000000..248f685 --- /dev/null +++ b/suds/xsd/deplist.py @@ -0,0 +1,126 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the (LGPL) GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program 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 Library Lesser General Public License for more details at +# ( http://www.gnu.org/licenses/lgpl.html ). +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# written by: Jeff Ortel ( jortel@redhat.com ) + +""" +The I{depsolve} module defines a class for performing dependancy solving. +""" + +from logging import getLogger +from suds import * + +log = getLogger(__name__) + + +class DepList: + """ + Dependancy solving list. + Items are tuples: (object, (deps,)) + @ivar raw: The raw (unsorted) items. + @type raw: list + @ivar index: The index of (unsorted) items. + @type index: list + @ivar stack: The sorting stack. + @type stack: list + @ivar pushed: A set of items pushed. This is an effecient way to keep + track of the items we've pushed. + @type stack: list + @ivar sorted The sorted list of items. + @type sorted: list + """ + + def __init__(self): + """ """ + self.raw = [] + self.index = {} + self.stack = [] + self.pushed = None + self.sorted = None + + def add(self, *items): + """ + Add items to be sorted. + @param items: One or more items to be added. + @type items: I{item} + @return: self + @rtype: L{DepList} + """ + for item in items: + self.raw.append(item) + self.index[item[0]] = item + return self + + def sort(self): + """ + Sort the list based on dependancies. + @return: The sorted items. + @rtype: list + """ + self.sorted = list() + self.pushed = set() + for item in self.raw: + self.push(item) + while len(self.stack): + self.pop() + self.raw = self.sorted + return self.sorted + + def push(self, item): + """ + Push and item onto the sorting stack. + @param item: An item to push. + @type item: I{item} + @return: The number of items pushed. + @rtype: int + """ + if item in self.pushed: + return 0 + self.pushed.add(item) + self.stack.append(item) + n = 1 + for d in item[1]: + n += 1 + dx = self.index.get(d) + if dx is None: + log.debug('dependency: %s not-found, skipped', Repr(d)) + continue + if self.push(dx) == 1: + self.pop() + n -= 1 + return n + + def pop(self): + """ + Pop the top item off the stack and append + it to the sorted list. + @return: self + @rtype: L{DepList} + """ + p = self.stack.pop() + self.sorted.append(p) + return self + + + +if __name__ == '__main__': + a = ('a', ()) + b = ('b', ('a',)) + c = ('c', ('a','b')) + d = ('d', ('c',)) + e = ('e', ('d','a')) + f = ('f', ('e','c','d','a')) + L = DepList() + L.add(c, e, d, b, f, a) + print [x[0] for x in L.sort()]
\ No newline at end of file diff --git a/suds/xsd/schema.py b/suds/xsd/schema.py index e1174d5..799d23a 100644 --- a/suds/xsd/schema.py +++ b/suds/xsd/schema.py @@ -30,6 +30,7 @@ from suds.xsd.sxbuiltin import * from suds.xsd.sxbasic import Factory as BasicFactory from suds.xsd.sxbuiltin import Factory as BuiltinFactory from suds.xsd.sxbase import SchemaObject +from suds.xsd.deplist import DepList from suds.sax import splitPrefix, Namespace log = getLogger(__name__) @@ -72,7 +73,6 @@ class SchemaCollection: """ Load the schema objects for the root nodes. - de-references schemas - - flatten schemas - merge schemas @return: The merged schema. @rtype: L{Schema} @@ -86,8 +86,6 @@ class SchemaCollection: log.debug('MERGED:\n%s', merged) merged.dereference() log.debug('MERGED: dereferenced:\n%s', merged) - merged.flatten() - log.debug('MERGED: dereferenced & flattened\n%s', merged) return merged def locate(self, ns): @@ -193,8 +191,6 @@ class Schema: log.debug('built:\n%s', self) self.dereference() log.debug('dereferenced:\n%s', self) - self.flatten() - log.debug('dereferenced & flattened:\n%s', self) def mktns(self): """ @@ -217,11 +213,10 @@ class Schema: """ if len(self.children): return - attributes, self.children = BasicFactory.build(self.root, self) - collated = BasicFactory.collate(attributes) - self.attributes = collated[2] + self.children = BasicFactory.build(self.root, self) collated = BasicFactory.collate(self.children) self.children = collated[0] + self.attributes = collated[2] self.imports = collated[1] self.elements = collated[3] self.types = collated[4] @@ -298,17 +293,21 @@ class Schema: Instruct all children to perform dereferencing. """ all = [] + indexes = {} for child in self.children: - child.contents(all) - for child in all: - child.dereference() - - def flatten(self): - """ - Instruct all children to I{flatten}. - """ - for child in self.children: - child.flatten() + child.content(all) + deplist = DepList() + for x in all: + midx, deps = x.dependencies() + item = (x, tuple(deps)) + deplist.add(item) + indexes[x] = midx + for x, deps in deplist.sort(): + midx = indexes.get(x) + if midx is None: continue + d = deps[midx] + log.debug('merging %s <== %s', Repr(x), Repr(d)) + x.merge(d) def custom(self, ref, context=None): """ diff --git a/suds/xsd/sxbase.py b/suds/xsd/sxbase.py index 9abefd8..634b98e 100644 --- a/suds/xsd/sxbase.py +++ b/suds/xsd/sxbase.py @@ -23,7 +23,6 @@ from logging import getLogger from suds import * from suds.xsd import * from suds.sax.element import Element -from copy import copy, deepcopy log = getLogger(__name__) @@ -42,17 +41,15 @@ class SchemaObject: @ivar nillable: A flag that inidcates that @nillable has a value of I{true}. @type nillable: boolean - @ivar children: A list of child xsd I{(non-attribute)} nodes - @type children: [L{SchemaObject},...] - @ivar attributes: A list of child xsd I{(attribute)} nodes - @type attributes: [L{SchemaObject},...] + @ivar rawchildren: A list raw of all children. + @type rawchildren: [L{SchemaObject},...] @ivar container: The <sequence/>,<all/> or <choice/> containing this object. @type container: L{SchemaObject} """ @classmethod - def prepend(cls, d, s, filter=None): + def prepend(cls, d, s, filter=Filter()): """ Prepend schema object's from B{s}ource list to the B{d}estination list while applying the filter. @@ -61,18 +58,16 @@ class SchemaObject: @param s: The source list. @type s: list @param filter: A filter that allows items to be prepended. - @type filter: L{ListFilter} + @type filter: L{Filter} """ - if filter is None: - filter = ListFilter() i = 0 for x in s: - if filter.permit(x): + if x in filter: d.insert(i, x) i += 1 @classmethod - def append(cls, d, s, filter=None): + def append(cls, d, s, filter=Filter()): """ Append schema object's from B{s}ource list to the B{d}estination list while applying the filter. @@ -81,12 +76,10 @@ class SchemaObject: @param s: The source list. @type s: list @param filter: A filter that allows items to be appended. - @type filter: L{ListFilter} + @type filter: L{Filter} """ - if filter is None: - filter = ListFilter() for item in s: - if filter.permit(item): + if item in filter: d.append(item) def __init__(self, schema, root): @@ -102,16 +95,61 @@ class SchemaObject: self.name = root.get('name') self.qname = (self.name, schema.tns[1]) self.type = root.get('type') - self.ref = [root.get('ref'), False] - self.ref[1] = ( self.ref[0] is not None ) + self.ref = root.get('ref') self.form_qualified = schema.form_qualified self.nillable = False self.inherited = False - self.children = [] - self.attributes = [] + self.rawchildren = [] self.container = None self.cache = {} - self.flattened = False + + def attributes(self, filter=Filter()): + """ + Get only the attribute content. + @param filter: A filter to constrain the result. + @type filter: L{Filter} + @return: A list attributes + @rtype: list + """ + for c in self: + if c.isattr() and c in filter: + yield c + + def children(self, filter=Filter()): + """ + Get only the I{direct} or non-attribute content. + @param filter: A filter to constrain the result. + @type filter: L{Filter} + @return: A list attributes + @rtype: list + """ + for c in self: + if not c.isattr() and c in filter: + yield c + + def get_attribute(self, name): + """ + Get (find) a I{non-attribute} attribute by name. + @param name: A attribute name. + @type name: str + @return: The requested child. + @rtype: L{SchemaObject} + """ + for child in self: + if child.isattr() and child.name == name: + return child + + def get_child(self, name): + """ + Get (find) a I{non-attribute} child by name. + @param name: A child name. + @type name: str + @return: The requested child. + @rtype: L{SchemaObject} + """ + for child in self.children(): + if child.any() or child.name == name: + return child def namespace(self): """ @@ -150,32 +188,6 @@ class SchemaObject: """ return self.cache.get(nobuiltin, self) - def get_child(self, name): - """ - Get (find) a I{non-attribute} child by name. - @param name: A child name. - @type name: str - @return: The requested child. - @rtype: L{SchemaObject} - """ - for child in self.children: - if child.any() or child.name == name: - return child - return None - - def get_attribute(self, name): - """ - Get (find) a I{non-attribute} attribute by name. - @param name: A attribute name. - @type name: str - @return: The requested child. - @rtype: L{SchemaObject} - """ - for child in self.attributes: - if child.name == name: - return child - return None - def sequence(self): """ Get whether this is an <xs:sequence/> @@ -264,7 +276,7 @@ class SchemaObject: classes = (self.__class__,) if self.qname == qref and self.__class__ in classes: return self - for c in self.children: + for c in self.rawchildren: p = c.find(qref, classes) if p is not None: return p @@ -286,58 +298,17 @@ class SchemaObject: """ return () - def flatten(self, parent=None): - """ - Walk the tree and invoke promote() on each node. This gives each - node the opportunity to flatten the tree as needed to remote - uninteresting nodes. Nodes that don't directly contribute to the - structure of the data are omitted. - """ - pa, pc = [],[] - if not self.flattened: - self.flattened = True - log.debug(Repr(self)) - for c in self.children: - a, c = c.flatten(self) - pa += a - pc += c - if parent is None: - self.attributes += pa - self.children = pc - else: - self.promote(pa, pc) - return (pa, pc) - - def promote(self, pa, pc): - """ - Promote children during the flattening proess. The object's - attributes and children are added to the B{p}romoted B{a}ttributes - and B{p}romoted B{c}hildren lists as they see fit. - @param pa: List of attributes to promote. - @type pa: [L{SchemaObject}] - @param pc: List of children to promote. - @type pc: [L{SchemaObject}] - """ - log.debug(Repr(self)) - filter = PromoteFilter() - self.prepend(pa, self.attributes) - self.prepend(pc, self.children, filter) - - def dereference(self): + def dependencies(self): """ - Walk the tree and invoke mutate() on each node. This gives each - node the opportunity to resolve references to other types - and mutate as needed. + Get a list of dependancies for dereferencing. + @return: A merge dependancy index and a list of dependancies. + @rtype: (int, [L{SchemaObject},...]) """ - if not self.ref[1]: return - log.debug(Repr(self)) - self.ref[1] = False - self.mutate() + return (None, []) - def mutate(self): + def merge(self, other): """ - Mutate into a I{true} type as defined by a reference to - another object. + Merge another object as needed. """ pass @@ -346,25 +317,35 @@ class SchemaObject: Mark this branch in the tree as inherited = true. """ self.inherited = True - for c in self.children: + for c in self: c.mark_inherited() - def contents(self, collection): + def content(self, collection=None, filter=Filter(), history=None): """ Get a I{flattened} list of this nodes contents. @param collection: A list to fill. @type collection: list + @param filter: A filter used to constrain the result. + @type filter: L{Filter} + @param history: The history list used to prevent cyclic dependency. + @type history: list @return: The filled list. @rtype: list """ - collection.append(self) - for a in self.attributes: - collection.append(a) - for c in self.children: - c.contents(collection) + if collection is None: + collection = [] + if history is None: + history = [] + if self in history: + return collection + history.append(self) + if self in filter: + collection.append(self) + for c in self.rawchildren: + c.content(collection, filter, history[:]) return collection - def str(self, indent=0): + def str(self, indent=0, history=None): """ Get a string representation of this object. @param indent: The indent. @@ -372,6 +353,11 @@ class SchemaObject: @return: A string. @rtype: str """ + if history is None: + history = [] + if self in history: + return '%s ...' % Repr(self) + history.append(self) tab = '%*s'%(indent*3, '') result = [] result.append('%s<%s' % (tab, self.id)) @@ -384,13 +370,11 @@ class SchemaObject: result.append(' %s="%s"' % (n, v)) if len(self): result.append('>') - for c in self.attributes: - result.append('\n') - result.append(c.str(indent+1)) - result.append('@') - for c in self.children: + for c in self.rawchildren: result.append('\n') - result.append(c.str(indent+1)) + result.append(c.str(indent+1, history[:])) + if c.isattr(): + result.append('@') result.append('\n%s' % tab) result.append('</%s>' % self.__class__.__name__) else: @@ -426,18 +410,112 @@ class SchemaObject: return myrep.encode('utf-8') def __len__(self): - return len(self.children)+len(self.attributes) + n = 0 + for x in self: n += 1 + return n + + def __iter__(self): + return Iter(self) def __getitem__(self, index): - return self.children[index] + i = 0 + for c in self: + if i == index: + return c - def __deepcopy__(self, memo={}): - clone = copy(self) - clone.attributes = deepcopy(self.attributes) - clone.children = deepcopy(self.children) - return clone +class Iter: + """ + The content iterator - used to iterate the L{Content} children. The iterator + provides a I{view} of the children that is free of container elements + such as <sequence/> and <choice/>. + @ivar stack: A stack used to control nesting. + @type stack: list + """ + + class Frame: + """ A content iterator frame. """ + + def __init__(self, sx): + """ + @param sx: A schema object. + @type sx: L{SchemaObject} + """ + self.items = sx.rawchildren + self.index = 0 + + def next(self): + """ + Get the I{next} item in the frame's collection. + @return: The next item or None + @rtype: L{SchemaObject} + """ + if self.index < len(self.items): + result = self.items[self.index] + self.index += 1 + return result + + def __init__(self, sx): + """ + @param sx: A schema object. + @type sx: L{SchemaObject} + """ + self.stack = [] + self.push(sx) + + def push(self, sx): + """ + Create a frame and push the specified object. + @param sx: A schema object to push. + @type sx: L{SchemaObject} + """ + self.stack.append(Iter.Frame(sx)) + + def pop(self): + """ + Pop the I{top} frame. + @return: The popped frame. + @rtype: L{Frame} + @raise StopIteration: when stack is empty. + """ + if len(self.stack): + return self.stack.pop() + else: + raise StopIteration() + + def top(self): + """ + Get the I{top} frame. + @return: The top frame. + @rtype: L{Frame} + @raise StopIteration: when stack is empty. + """ + if len(self.stack): + return self.stack[-1] + else: + raise StopIteration() + + def next(self): + """ + Get the next item. + @return: The next item being iterated. + @rtype: L{SchemaObject} + """ + frame = self.top() + while True: + result = frame.next() + if result is None: + self.pop() + return self.next() + if isinstance(result, Content): + return result + self.push(result) + return self.next() + def __iter__(self): + return self + + class XBuiltin(SchemaObject): """ Represents an (xsd) schema <xs:*/> node @@ -463,32 +541,9 @@ class XBuiltin(SchemaObject): return self -class Promotable(SchemaObject): +class Content(SchemaObject): """ - Represents I{promotable} schema objects. They are objects that - should be promoted during the flattening process. + This class represents those schema objects that represent + real XML document content. """ - - def __init__(self, schema, root): - """ - @param schema: The containing schema. - @type schema: L{schema.Schema} - @param root: The xml root node. - @type root: L{Element} - """ - SchemaObject.__init__(self, schema, root) - - -class ListFilter: - def permit(self, x): - return True - -class PromoteFilter(ListFilter): - def permit(self, x): - return isinstance(x, Promotable) - -class UniqueFilter(ListFilter): - def __init__(self, d): - self.ids = [m.id for m in d] - def permit(self, x): - return ( x.id not in self.ids )
\ No newline at end of file + pass diff --git a/suds/xsd/sxbasic.py b/suds/xsd/sxbasic.py index e7fff92..67b13e3 100644 --- a/suds/xsd/sxbasic.py +++ b/suds/xsd/sxbasic.py @@ -28,7 +28,6 @@ from suds.sax import splitPrefix, Namespace from suds.sax.parser import Parser from suds.transport import TransportError from urlparse import urljoin -from copy import copy, deepcopy log = getLogger(__name__) @@ -89,21 +88,16 @@ class Factory: @return: A schema object graph. @rtype: L{sxbase.SchemaObject} """ - attributes = [] children = [] for node in root.getChildren(ns=Namespace.xsdns): if '*' in filter or node.name in filter: child = cls.create(node, schema) if child is None: continue - if child.isattr(): - attributes.append(child) - else: - children.append(child) - a, c = cls.build(node, schema, child.childtags()) - child.attributes = a - child.children = c - return (attributes, children) + children.append(child) + c = cls.build(node, schema, child.childtags()) + child.rawchildren = c + return children @classmethod def collate(cls, children): @@ -170,7 +164,7 @@ class Complex(SchemaObject): return self.__derived except: self.__derived = False - for c in self.children: + for c in self: if c.inherited: self.__derived = True break @@ -246,19 +240,28 @@ class Group(SchemaObject): else: return self.container.optional() - def mutate(self): - """ - Mutate into a I{true} type as defined by a reference to - another object. - """ - defns = self.default_namespace() - qref = qualify(self.ref[0], self.root, defns) - query = GroupQuery(qref) - g = query.execute(self.schema) - if g is None: - log.debug(self.schema) - raise TypeNotFound(qref) - self.merge(deepcopy(g)) + def dependencies(self): + """ + Get a list of dependancies for dereferencing. + @return: A merge dependancy index and a list of dependancies. + @rtype: (int, [L{SchemaObject},...]) + """ + deps = [] + midx = None + if self.ref is not None: + defns = self.default_namespace() + qref = qualify(self.ref, self.root, defns) + query = GroupQuery(qref) + g = query.execute(self.schema) + if g is None: + log.debug(self.schema) + raise TypeNotFound(qref) + deps.append(g) + midx = 0 + for c in self.content([], Filter(False, self)): + if c.ref is not None: + deps.append(c) + return (midx, deps) def merge(self, g): """ @@ -266,10 +269,9 @@ class Group(SchemaObject): @param g: A resoleve reference. @type g: L{Group} """ - g.dereference() self.name = g.name self.qname = g.qname - self.children = g.children + self.rawchildren = g.rawchildren def description(self): """ @@ -306,19 +308,28 @@ class AttributeGroup(SchemaObject): """ return ('attribute', 'attributeGroup') - def mutate(self): - """ - Mutate into a I{true} type as defined by a reference to - another object. - """ - defns = self.default_namespace() - qref = qualify(self.ref[0], self.root, defns) - query = AttrGroupQuery(qref) - ag = query.execute(self.schema) - if ag is None: - log.debug(self.schema) - raise TypeNotFound(qref) - self.merge(deepcopy(ag)) + def dependencies(self): + """ + Get a list of dependancies for dereferencing. + @return: A merge dependancy index and a list of dependancies. + @rtype: (int, [L{SchemaObject},...]) + """ + deps = [] + midx = None + if self.ref is not None: + defns = self.default_namespace() + qref = qualify(self.ref, self.root, defns) + query = AttrGroupQuery(qref) + ag = query.execute(self.schema) + if ag is None: + log.debug(self.schema) + raise TypeNotFound(qref) + deps.append(ag) + midx = 0 + for c in self.content([], Filter(False, self)): + if c.ref is not None: + deps.append(c) + return (midx, deps) def merge(self, ag): """ @@ -326,11 +337,9 @@ class AttributeGroup(SchemaObject): @param ag: A resoleve reference. @type ag: L{AttributeGroup} """ - ag.dereference() self.name = ag.name self.qname = ag.qname - self.attributes = ag.attributes - self.children = ag.children + self.rawchildren = ag.rawchildren def description(self): """ @@ -360,7 +369,7 @@ class Simple(SchemaObject): @return: True if any, else False @rtype: boolean """ - for c in self.children: + for c in self: if isinstance(c, Enumeration): return True return False @@ -387,9 +396,7 @@ class Restriction(SchemaObject): @type root: L{sax.element.Element} """ SchemaObject.__init__(self, schema, root) - base = root.get('base') - self.ref = [base, True] - self.ref[1] = ( base is not None ) + self.ref = root.get('base') def childtags(self): """ @@ -399,21 +406,29 @@ class Restriction(SchemaObject): """ return ('enumeration', 'attribute', 'attributeGroup') - def mutate(self): - """ - Mutate into a I{true} type as defined by a reference to - another object. - """ - log.debug(Repr(self)) - defns = self.default_namespace() - qref = qualify(self.ref[0], self.root, defns) - query = TypeQuery(qref) - super = query.execute(self.schema) - if super is None: - log.debug(self.schema) - raise TypeNotFound(qref) - if not super.builtin(): - self.merge(deepcopy(super)) + def dependencies(self): + """ + Get a list of dependancies for dereferencing. + @return: A merge dependancy index and a list of dependancies. + @rtype: (int, [L{SchemaObject},...]) + """ + deps = [] + midx = None + if self.ref is not None: + defns = self.default_namespace() + qref = qualify(self.ref, self.root, defns) + query = TypeQuery(qref) + super = query.execute(self.schema) + if super is None: + log.debug(self.schema) + raise TypeNotFound(qref) + if not super.builtin(): + deps.append(super) + midx = 0 + for c in self.content([], Filter(False, self)): + if c.ref is not None: + deps.append(c) + return (midx, deps) def merge(self, b): """ @@ -421,13 +436,10 @@ class Restriction(SchemaObject): @param b: A resolved base object. @type b: L{SchemaObject} """ - b.dereference() - filter = UniqueFilter(self.attributes) - self.prepend(self.attributes, b.attributes, filter) - filter = UniqueFilter(self.children) - for c in b.children: + filter = Filter(False, self.rawchildren) + for c in b.rawchildren: c.mark_inherited() - self.prepend(self.children, b.children, filter) + self.prepend(self.rawchildren, b.rawchildren, filter) def description(self): """ @@ -464,20 +476,6 @@ class Collection(SchemaObject): @rtype: [str,...] """ return ('element', 'sequence', 'all', 'choice', 'any', 'group') - - def promote(self, pa, pc): - """ - Promote children during the flattening proess. The object's - attributes and children are added to the B{p}romoted B{a}ttributes - and B{p}romoted B{c}hildren lists as they see fit. - @param pa: List of attributes to promote. - @type pa: [L{SchemaObject}] - @param pc: List of children to promote. - @type pc: [L{SchemaObject}] - """ - for c in self.children: - c.container = self - SchemaObject.promote(self, pa, pc) def unbounded(self): """ @@ -564,7 +562,7 @@ class SimpleContent(SchemaObject): return ('extension', 'restriction') -class Enumeration(Promotable): +class Enumeration(Content): """ Represents an (xsd) schema <xs:enumeration/> node """ @@ -576,11 +574,19 @@ class Enumeration(Promotable): @param root: The xml root node. @type root: L{sax.element.Element} """ - Promotable.__init__(self, schema, root) + Content.__init__(self, schema, root) self.name = root.get('value') + + def enum(self): + """ + Get whether this is an enumeration. + @return: True + @rtype: boolean + """ + return True -class Element(Promotable): +class Element(Content): """ Represents an (xsd) schema <xs:element/> node. """ @@ -592,7 +598,7 @@ class Element(Promotable): @param root: The xml root node. @type root: L{sax.element.Element} """ - Promotable.__init__(self, schema, root) + Content.__init__(self, schema, root) self.min = root.get('minOccurs', default='1') self.max = root.get('maxOccurs', default='1') a = root.get('form') @@ -682,19 +688,28 @@ class Element(Promotable): result = resolved.resolve(nobuiltin) return result - def mutate(self): - """ - Mutate into a I{true} type as defined by a reference to - another object. - """ - defns = self.default_namespace() - qref = qualify(self.ref[0], self.root, defns) - query = ElementQuery(qref) - e = query.execute(self.schema) - if e is None: - log.debug(self.schema) - raise TypeNotFound(qref) - self.merge(deepcopy(e)) + def dependencies(self): + """ + Get a list of dependancies for dereferencing. + @return: A merge dependancy index and a list of dependancies. + @rtype: (int, [L{SchemaObject},...]) + """ + deps = [] + midx = None + if self.ref is not None: + defns = self.default_namespace() + qref = qualify(self.ref, self.root, defns) + query = ElementQuery(qref) + e = query.execute(self.schema) + if e is None: + log.debug(self.schema) + raise TypeNotFound(qref) + deps.append(e) + midx = 0 + for c in self.content([], Filter(False, self)): + if c.ref is not None: + deps.append(c) + return (midx, deps) def merge(self, e): """ @@ -702,29 +717,11 @@ class Element(Promotable): @param e: A resoleve reference. @type e: L{Element} """ - e.dereference() self.name = e.name self.qname = e.qname self.type = e.type - self.attributes = e.attributes - self.children = e.children - - def promote(self, pa, pc): - """ - Promote children during the flattening proess. The object's - attributes and children are added to the B{p}romoted B{a}ttributes - and B{p}romoted B{c}hildren lists as they see fit. - @param pa: List of attributes to promote. - @type pa: [L{SchemaObject}] - @param pc: List of children to promote. - @type pc: [L{SchemaObject}] - """ - if len(self): - log.debug(Repr(self)) - self.attributes += pa - self.children = copy(pc) - del pa[:] - del pc[:] + self.rawchildren = e.rawchildren + def description(self): """ @@ -732,7 +729,7 @@ class Element(Promotable): @return: A dictionary of relavent attributes. @rtype: [str,...] """ - return ('name', 'type', 'inherited') + return ('name', 'ref', 'type', 'inherited') def container_unbounded(self): """ get whether container is unbounded """ @@ -771,9 +768,7 @@ class Extension(SchemaObject): @type root: L{sax.element.Element} """ SchemaObject.__init__(self, schema, root) - base = root.get('base') - self.ref = [base, True] - self.ref[1] = ( base is not None ) + self.ref = root.get('base') def childtags(self): """ @@ -783,20 +778,29 @@ class Extension(SchemaObject): """ return ('attribute', 'attributeGroup', 'sequence', 'all', 'choice', 'group') - def mutate(self): - """ - Mutate into a I{true} type as defined by a reference to - another object. - """ - log.debug(Repr(self)) - defns = self.default_namespace() - qref = qualify(self.ref[0], self.root, defns) - query = TypeQuery(qref) - super = query.execute(self.schema) - if super is None: - log.debug(self.schema) - raise TypeNotFound(qref) - self.merge(deepcopy(super)) + def dependencies(self): + """ + Get a list of dependancies for dereferencing. + @return: A merge dependancy index and a list of dependancies. + @rtype: (int, [L{SchemaObject},...]) + """ + deps = [] + midx = None + if self.ref is not None: + defns = self.default_namespace() + qref = qualify(self.ref, self.root, defns) + query = TypeQuery(qref) + super = query.execute(self.schema) + if super is None: + log.debug(self.schema) + raise TypeNotFound(qref) + if not super.builtin(): + deps.append(super) + midx = 0 + for c in self.content([], Filter(False, self)): + if c.ref is not None: + deps.append(c) + return (midx, deps) def merge(self, b): """ @@ -804,13 +808,10 @@ class Extension(SchemaObject): @param b: A resolved base object. @type b: L{SchemaObject} """ - b.dereference() - filter = UniqueFilter(self.attributes) - self.prepend(self.attributes, b.attributes, filter) - filter = UniqueFilter(self.children) - for c in b.children: + filter = Filter(False, self.rawchildren) + for c in b.rawchildren: c.mark_inherited() - self.prepend(self.children, b.children, filter) + self.prepend(self.rawchildren, b.rawchildren, filter) def description(self): """ @@ -909,7 +910,7 @@ class Include(Import): pass -class Attribute(Promotable): +class Attribute(Content): """ Represents an (xsd) <attribute/> node """ @@ -921,7 +922,7 @@ class Attribute(Promotable): @param root: The xml root node. @type root: L{sax.element.Element} """ - Promotable.__init__(self, schema, root) + Content.__init__(self, schema, root) self.use = root.get('use', default='') def isattr(self): @@ -948,19 +949,28 @@ class Attribute(Promotable): """ return ( self.use != 'required' ) - def mutate(self): - """ - Mutate into a I{true} type as defined by a reference to - another object. - """ - defns = self.default_namespace() - qref = qualify(self.ref[0], self.root, defns) - query = AttrQuery(qref) - a = query.execute(self.schema) - if a is None: - log.debug(self.schema) - raise TypeNotFound(qref) - self.merge(deepcopy(a)) + def dependencies(self): + """ + Get a list of dependancies for dereferencing. + @return: A merge dependancy index and a list of dependancies. + @rtype: (int, [L{SchemaObject},...]) + """ + deps = [] + midx = None + if self.ref is not None: + defns = self.default_namespace() + qref = qualify(self.ref, self.root, defns) + query = AttrQuery(qref) + a = query.execute(self.schema) + if a is None: + log.debug(self.schema) + raise TypeNotFound(qref) + deps.append(a) + midx = 0 + for c in self.content([], Filter(False, self)): + if c.ref is not None: + deps.append(c) + return (midx, deps) def merge(self, a): """ @@ -968,7 +978,6 @@ class Attribute(Promotable): @param a: A resoleve reference. @type a: L{Attribute} """ - a.dereference() self.name = a.name self.qname = a.qname self.type = a.type @@ -982,7 +991,7 @@ class Attribute(Promotable): return ('name', 'ref', 'type') -class Any(Promotable): +class Any(Content): """ Represents an (xsd) <any/> node """ @@ -1014,6 +1023,7 @@ class Any(Promotable): @rtype: boolean """ return True + ####################################################### |