Package suds :: Package xsd :: Module sxbase
[hide private]
[frames] | no frames]

Source Code for Module suds.xsd.sxbase

  1  # This program is free software; you can redistribute it and/or modify 
  2  # it under the terms of the (LGPL) GNU Lesser General Public License as 
  3  # published by the Free Software Foundation; either version 3 of the  
  4  # License, or (at your option) any later version. 
  5  # 
  6  # This program is distributed in the hope that it will be useful, 
  7  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  8  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  9  # GNU Library Lesser General Public License for more details at 
 10  # ( http://www.gnu.org/licenses/lgpl.html ). 
 11  # 
 12  # You should have received a copy of the GNU Lesser General Public License 
 13  # along with this program; if not, write to the Free Software 
 14  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 15  # written by: Jeff Ortel ( jortel@redhat.com ) 
 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__) 
29 30 31 -class SchemaObject(object):
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
52 - def prepend(cls, d, s, filter=Filter()):
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
70 - def append(cls, d, s, filter=Filter()):
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
85 - def __init__(self, schema, root):
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
107 - def attributes(self, filter=Filter()):
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
121 - def children(self, filter=Filter()):
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
135 - def get_attribute(self, name):
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
148 - def get_child(self, name):
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
161 - def namespace(self, prefix=None):
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
174 - def default_namespace(self):
175 return self.root.defaultNamespace()
176
177 - def unbounded(self):
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
191 - def optional(self):
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
202 - def required(self):
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
221 - def sequence(self):
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
229 - def xslist(self):
230 """ 231 Get whether this is an <xs:list/> 232 @return: True if any, else False 233 @rtype: boolean 234 """ 235 return False
236
237 - def all(self):
238 """ 239 Get whether this is an <xs:all/> 240 @return: True if any, else False 241 @rtype: boolean 242 """ 243 return False
244
245 - def choice(self):
246 """ 247 Get whether this is n <xs:choice/> 248 @return: True if any, else False 249 @rtype: boolean 250 """ 251 return False
252
253 - def any(self):
254 """ 255 Get whether this is an <xs:any/> 256 @return: True if any, else False 257 @rtype: boolean 258 """ 259 return False
260
261 - def builtin(self):
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
269 - def enum(self):
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
277 - def isattr(self):
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
285 - def extension(self):
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
293 - def restriction(self):
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
301 - def mixed(self):
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
328 - def translate(self, value, topython=True):
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
336 - def childtags(self):
337 """ 338 Get a list of valid child tag names. 339 @return: A list of child tag names. 340 @rtype: [str,...] 341 """ 342 return ()
343
344 - def dependencies(self):
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
352 - def autoqualified(self):
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
361 - def qualify(self):
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
382 - def merge(self, other):
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
464 - def description(self):
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
472 - def __str__(self):
473 return unicode(self).encode('utf-8')
474
475 - def __unicode__(self):
476 return unicode(self.str())
477
478 - def __repr__(self):
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
492 - def __len__(self):
493 n = 0 494 for x in self: n += 1 495 return n
496
497 - def __iter__(self):
498 return Iter(self)
499
500 - def __getitem__(self, index):
501 i = 0 502 for c in self: 503 if i == index: 504 return c
505
506 507 -class Iter:
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
516 - class Frame:
517 """ A content iterator frame. """ 518
519 - def __init__(self, sx):
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
528 - def next(self):
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
539 - def __init__(self, sx):
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
555 - def pop(self):
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
567 - def top(self):
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
579 - def next(self):
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
598 - def __iter__(self):
599 return self
600
601 602 -class XBuiltin(SchemaObject):
603 """ 604 Represents an (xsd) schema <xs:*/> node 605 """ 606
607 - def __init__(self, schema, name):
608 """ 609 @param schema: The containing schema. 610 @type schema: L{schema.Schema} 611 """ 612 root = Element(name) 613 SchemaObject.__init__(self, schema, root) 614 self.name = name 615 self.nillable = True
616
617 - def namespace(self, prefix=None):
618 return Namespace.xsdns
619
620 - def builtin(self):
621 return True
622
623 - def resolve(self, nobuiltin=False):
624 return self
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
634 635 -class NodeFinder:
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 """
644 - def __init__(self, matcher, limit=0):
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