summaryrefslogtreecommitdiff
path: root/suds
diff options
context:
space:
mode:
authorjortel <devnull@localhost>2009-01-16 20:23:56 +0000
committerjortel <devnull@localhost>2009-01-16 20:23:56 +0000
commitcf7a832de9a6ab3cbc302d025af432e906476d52 (patch)
tree078b3ab38c8d6d0689f088d15c1d99a8bfa1f160 /suds
parent9bfd3bd2308962c73a1280be14aded40845ba40c (diff)
downloadsuds-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__.py2
-rw-r--r--suds/bindings/document.py4
-rw-r--r--suds/builder.py11
-rw-r--r--suds/client.py5
-rw-r--r--suds/servicedefinition.py5
-rw-r--r--suds/xsd/__init__.py13
-rw-r--r--suds/xsd/deplist.py126
-rw-r--r--suds/xsd/schema.py35
-rw-r--r--suds/xsd/sxbase.py341
-rw-r--r--suds/xsd/sxbasic.py328
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
+
#######################################################