1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 The I{sxbase} module provides I{base} classes that represent
19 schema objects.
20 """
21
22 from logging import getLogger
23 from suds import *
24 from suds.xsd import *
25 from suds.sax.element import Element
26 from suds.sax import Namespace
27
28 log = getLogger(__name__)
32 """
33 A schema object is an extension to object object with
34 with schema awareness.
35 @ivar root: The XML root element.
36 @type root: L{Element}
37 @ivar schema: The schema containing this object.
38 @type schema: L{schema.Schema}
39 @ivar form_qualified: A flag that inidcates that @elementFormDefault
40 has a value of I{qualified}.
41 @type form_qualified: boolean
42 @ivar nillable: A flag that inidcates that @nillable
43 has a value of I{true}.
44 @type nillable: boolean
45 @ivar default: The default value.
46 @type default: object
47 @ivar rawchildren: A list raw of all children.
48 @type rawchildren: [L{SchemaObject},...]
49 """
50
51 @classmethod
53 """
54 Prepend schema object's from B{s}ource list to
55 the B{d}estination list while applying the filter.
56 @param d: The destination list.
57 @type d: list
58 @param s: The source list.
59 @type s: list
60 @param filter: A filter that allows items to be prepended.
61 @type filter: L{Filter}
62 """
63 i = 0
64 for x in s:
65 if x in filter:
66 d.insert(i, x)
67 i += 1
68
69 @classmethod
71 """
72 Append schema object's from B{s}ource list to
73 the B{d}estination list while applying the filter.
74 @param d: The destination list.
75 @type d: list
76 @param s: The source list.
77 @type s: list
78 @param filter: A filter that allows items to be appended.
79 @type filter: L{Filter}
80 """
81 for item in s:
82 if item in filter:
83 d.append(item)
84
86 """
87 @param schema: The containing schema.
88 @type schema: L{schema.Schema}
89 @param root: The xml root node.
90 @type root: L{Element}
91 """
92 self.schema = schema
93 self.root = root
94 self.id = objid(self)
95 self.name = root.get('name')
96 self.qname = (self.name, schema.tns[1])
97 self.min = root.get('minOccurs')
98 self.max = root.get('maxOccurs')
99 self.type = root.get('type')
100 self.ref = root.get('ref')
101 self.form_qualified = schema.form_qualified
102 self.nillable = False
103 self.default = root.get('default')
104 self.rawchildren = []
105 self.cache = {}
106
108 """
109 Get only the attribute content.
110 @param filter: A filter to constrain the result.
111 @type filter: L{Filter}
112 @return: A list of tuples (attr, ancestry)
113 @rtype: [(L{SchemaObject}, [L{SchemaObject},..]),..]
114 """
115 result = []
116 for child, ancestry in self:
117 if child.isattr() and child in filter:
118 result.append((child, ancestry))
119 return result
120
122 """
123 Get only the I{direct} or non-attribute content.
124 @param filter: A filter to constrain the result.
125 @type filter: L{Filter}
126 @return: A list tuples: (child, ancestry)
127 @rtype: [(L{SchemaObject}, [L{SchemaObject},..]),..]
128 """
129 result = []
130 for child, ancestry in self:
131 if not child.isattr() and child in filter:
132 result.append((child, ancestry))
133 return result
134
136 """
137 Get (find) a I{non-attribute} attribute by name.
138 @param name: A attribute name.
139 @type name: str
140 @return: A tuple: the requested (attribute, ancestry).
141 @rtype: (L{SchemaObject}, [L{SchemaObject},..])
142 """
143 for child, ancestry in self.attributes():
144 if child.name == name:
145 return (child, ancestry)
146 return (None, [])
147
149 """
150 Get (find) a I{non-attribute} child by name.
151 @param name: A child name.
152 @type name: str
153 @return: A tuple: the requested (child, ancestry).
154 @rtype: (L{SchemaObject}, [L{SchemaObject},..])
155 """
156 for child, ancestry in self.children():
157 if child.any() or child.name == name:
158 return (child, ancestry)
159 return (None, [])
160
162 """
163 Get this properties namespace
164 @param prefix: The default prefix.
165 @type prefix: str
166 @return: The schema's target namespace
167 @rtype: (I{prefix},I{URI})
168 """
169 ns = self.schema.tns
170 if ns[0] is None:
171 ns = (prefix, ns[1])
172 return ns
173
176
178 """
179 Get whether this node is unbounded I{(a collection)}
180 @return: True if unbounded, else False.
181 @rtype: boolean
182 """
183 max = self.max
184 if max is None:
185 max = '1'
186 if max.isdigit():
187 return (int(max) > 1)
188 else:
189 return ( max == 'unbounded' )
190
192 """
193 Get whether this type is optional.
194 @return: True if optional, else False
195 @rtype: boolean
196 """
197 min = self.min
198 if min is None:
199 min = '1'
200 return ( min == '0' )
201
203 """
204 Get whether this type is required.
205 @return: True if required, else False
206 @rtype: boolean
207 """
208 return ( not self.optional() )
209
210
211 - def resolve(self, nobuiltin=False):
212 """
213 Resolve and return the nodes true self.
214 @param nobuiltin: Flag indicates that resolution must
215 not continue to include xsd builtins.
216 @return: The resolved (true) type.
217 @rtype: L{SchemaObject}
218 """
219 return self.cache.get(nobuiltin, self)
220
222 """
223 Get whether this is an <xs:sequence/>
224 @return: True if <xs:sequence/>, else False
225 @rtype: boolean
226 """
227 return False
228
230 """
231 Get whether this is an <xs:list/>
232 @return: True if any, else False
233 @rtype: boolean
234 """
235 return False
236
238 """
239 Get whether this is an <xs:all/>
240 @return: True if any, else False
241 @rtype: boolean
242 """
243 return False
244
246 """
247 Get whether this is n <xs:choice/>
248 @return: True if any, else False
249 @rtype: boolean
250 """
251 return False
252
254 """
255 Get whether this is an <xs:any/>
256 @return: True if any, else False
257 @rtype: boolean
258 """
259 return False
260
262 """
263 Get whether this is a schema-instance (xs) type.
264 @return: True if any, else False
265 @rtype: boolean
266 """
267 return False
268
270 """
271 Get whether this is a simple-type containing an enumeration.
272 @return: True if any, else False
273 @rtype: boolean
274 """
275 return False
276
278 """
279 Get whether the object is a schema I{attribute} definition.
280 @return: True if an attribute, else False.
281 @rtype: boolean
282 """
283 return False
284
286 """
287 Get whether the object is an extension of another type.
288 @return: True if an extension, else False.
289 @rtype: boolean
290 """
291 return False
292
294 """
295 Get whether the object is an restriction of another type.
296 @return: True if an restriction, else False.
297 @rtype: boolean
298 """
299 return False
300
302 """
303 Get whether this I{mixed} content.
304 """
305 return False
306
307 - def find(self, qref, classes=()):
308 """
309 Find a referenced type in self or children.
310 @param qref: A qualified reference.
311 @type qref: qref
312 @param classes: A list of classes used to qualify the match.
313 @type classes: [I{class},...]
314 @return: The referenced type.
315 @rtype: L{SchemaObject}
316 @see: L{qualify()}
317 """
318 if not len(classes):
319 classes = (self.__class__,)
320 if self.qname == qref and self.__class__ in classes:
321 return self
322 for c in self.rawchildren:
323 p = c.find(qref, classes)
324 if p is not None:
325 return p
326 return None
327
329 """
330 Translate a value (type) to/from a python type.
331 @param value: A value to translate.
332 @return: The converted I{language} type.
333 """
334 return value
335
343
345 """
346 Get a list of dependancies for dereferencing.
347 @return: A merge dependancy index and a list of dependancies.
348 @rtype: (int, [L{SchemaObject},...])
349 """
350 return (None, [])
351
353 """
354 The list of I{auto} qualified attribute values.
355 Qualification means to convert values into I{qref}.
356 @return: A list of attibute names.
357 @rtype: list
358 """
359 return ['type', 'ref']
360
362 """
363 Convert attribute values, that are references to other
364 objects, into I{qref}. Qualfied using default document namespace.
365 Since many wsdls are written improperly: when the document does
366 not define a default namespace, the schema target namespace is used
367 to qualify references.
368 """
369 defns = self.root.defaultNamespace()
370 if Namespace.none(defns):
371 defns = self.schema.tns
372 for a in self.autoqualified():
373 ref = getattr(self, a)
374 if ref is None:
375 continue
376 if isqref(ref):
377 continue
378 qref = qualify(ref, self.root, defns)
379 log.debug('%s, convert %s="%s" to %s', self.id, a, ref, qref)
380 setattr(self, a, qref)
381
383 """
384 Merge another object as needed.
385 """
386 other.qualify()
387 for n in ('name',
388 'qname',
389 'min',
390 'max',
391 'default',
392 'type',
393 'nillable',
394 'form_qualified',):
395 if getattr(self, n) is not None:
396 continue
397 v = getattr(other, n)
398 if v is None:
399 continue
400 setattr(self, n, v)
401
402
403 - def content(self, collection=None, filter=Filter(), history=None):
404 """
405 Get a I{flattened} list of this nodes contents.
406 @param collection: A list to fill.
407 @type collection: list
408 @param filter: A filter used to constrain the result.
409 @type filter: L{Filter}
410 @param history: The history list used to prevent cyclic dependency.
411 @type history: list
412 @return: The filled list.
413 @rtype: list
414 """
415 if collection is None:
416 collection = []
417 if history is None:
418 history = []
419 if self in history:
420 return collection
421 history.append(self)
422 if self in filter:
423 collection.append(self)
424 for c in self.rawchildren:
425 c.content(collection, filter, history[:])
426 return collection
427
428 - def str(self, indent=0, history=None):
429 """
430 Get a string representation of this object.
431 @param indent: The indent.
432 @type indent: int
433 @return: A string.
434 @rtype: str
435 """
436 if history is None:
437 history = []
438 if self in history:
439 return '%s ...' % Repr(self)
440 history.append(self)
441 tab = '%*s'%(indent*3, '')
442 result = []
443 result.append('%s<%s' % (tab, self.id))
444 for n in self.description():
445 if not hasattr(self, n):
446 continue
447 v = getattr(self, n)
448 if v is None:
449 continue
450 result.append(' %s="%s"' % (n, v))
451 if len(self):
452 result.append('>')
453 for c in self.rawchildren:
454 result.append('\n')
455 result.append(c.str(indent+1, history[:]))
456 if c.isattr():
457 result.append('@')
458 result.append('\n%s' % tab)
459 result.append('</%s>' % self.__class__.__name__)
460 else:
461 result.append(' />')
462 return ''.join(result)
463
465 """
466 Get the names used for str() and repr() description.
467 @return: A dictionary of relavent attributes.
468 @rtype: [str,...]
469 """
470 return ()
471
473 return unicode(self).encode('utf-8')
474
476 return unicode(self.str())
477
479 s = []
480 s.append('<%s' % self.id)
481 for n in self.description():
482 if not hasattr(self, n):
483 continue
484 v = getattr(self, n)
485 if v is None:
486 continue
487 s.append(' %s="%s"' % (n, v))
488 s.append(' />')
489 myrep = ''.join(s)
490 return myrep.encode('utf-8')
491
493 n = 0
494 for x in self: n += 1
495 return n
496
499
501 i = 0
502 for c in self:
503 if i == index:
504 return c
505
508 """
509 The content iterator - used to iterate the L{Content} children. The iterator
510 provides a I{view} of the children that is free of container elements
511 such as <sequence/> and <choice/>.
512 @ivar stack: A stack used to control nesting.
513 @type stack: list
514 """
515
517 """ A content iterator frame. """
518
520 """
521 @param sx: A schema object.
522 @type sx: L{SchemaObject}
523 """
524 self.sx = sx
525 self.items = sx.rawchildren
526 self.index = 0
527
529 """
530 Get the I{next} item in the frame's collection.
531 @return: The next item or None
532 @rtype: L{SchemaObject}
533 """
534 if self.index < len(self.items):
535 result = self.items[self.index]
536 self.index += 1
537 return result
538
540 """
541 @param sx: A schema object.
542 @type sx: L{SchemaObject}
543 """
544 self.stack = []
545 self.push(sx)
546
547 - def push(self, sx):
548 """
549 Create a frame and push the specified object.
550 @param sx: A schema object to push.
551 @type sx: L{SchemaObject}
552 """
553 self.stack.append(Iter.Frame(sx))
554
556 """
557 Pop the I{top} frame.
558 @return: The popped frame.
559 @rtype: L{Frame}
560 @raise StopIteration: when stack is empty.
561 """
562 if len(self.stack):
563 return self.stack.pop()
564 else:
565 raise StopIteration()
566
568 """
569 Get the I{top} frame.
570 @return: The top frame.
571 @rtype: L{Frame}
572 @raise StopIteration: when stack is empty.
573 """
574 if len(self.stack):
575 return self.stack[-1]
576 else:
577 raise StopIteration()
578
580 """
581 Get the next item.
582 @return: A tuple: the next (child, ancestry).
583 @rtype: (L{SchemaObject}, [L{SchemaObject},..])
584 @raise StopIteration: A the end.
585 """
586 frame = self.top()
587 while True:
588 result = frame.next()
589 if result is None:
590 self.pop()
591 return self.next()
592 if isinstance(result, Content):
593 ancestry = [f.sx for f in self.stack]
594 return (result, ancestry)
595 self.push(result)
596 return self.next()
597
600
603 """
604 Represents an (xsd) schema <xs:*/> node
605 """
606
616
619
622
623 - def resolve(self, nobuiltin=False):
625
626
627 -class Content(SchemaObject):
628 """
629 This class represents those schema objects that represent
630 real XML document content.
631 """
632 pass
633
636 """
637 Find nodes based on flexable criteria. The I{matcher} is
638 may be any object that implements a match(n) method.
639 @ivar matcher: An object used as criteria for match.
640 @type matcher: I{any}.match(n)
641 @ivar limit: Limit the number of matches. 0=unlimited.
642 @type limit: int
643 """
645 """
646 @param matcher: An object used as criteria for match.
647 @type matcher: I{any}.match(n)
648 @param limit: Limit the number of matches. 0=unlimited.
649 @type limit: int
650 """
651 self.matcher = matcher
652 self.limit = limit
653
654 - def find(self, node, list):
655 """
656 Traverse the tree looking for matches.
657 @param node: A node to match on.
658 @type node: L{SchemaObject}
659 @param list: A list to fill.
660 @type list: list
661 """
662 if self.matcher.match(node):
663 list.append(node)
664 self.limit -= 1
665 if self.limit == 0:
666 return
667 for c in node.rawchildren:
668 self.find(c, list)
669 return self
670