Package suds :: Package sax :: Module element
[hide private]
[frames] | no frames]

Source Code for Module suds.sax.element

   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  Provides XML I{element} classes. 
  19  """ 
  20   
  21  from logging import getLogger 
  22  from suds import * 
  23  from suds.sax import * 
  24  from suds.sax.text import Text 
  25  from suds.sax.attribute import Attribute 
  26  import sys  
  27  if sys.version_info < (2, 4, 0):  
  28      from sets import Set as set  
  29      del sys  
  30   
  31  log = getLogger(__name__) 
32 33 -class Element:
34 """ 35 An XML element object. 36 @ivar parent: The node containing this attribute 37 @type parent: L{Element} 38 @ivar prefix: The I{optional} namespace prefix. 39 @type prefix: basestring 40 @ivar name: The I{unqualified} name of the attribute 41 @type name: basestring 42 @ivar expns: An explicit namespace (xmlns="..."). 43 @type expns: (I{prefix}, I{name}) 44 @ivar nsprefixes: A mapping of prefixes to namespaces. 45 @type nsprefixes: dict 46 @ivar attributes: A list of XML attributes. 47 @type attributes: [I{Attribute},] 48 @ivar text: The element's I{text} content. 49 @type text: basestring 50 @ivar children: A list of child elements. 51 @type children: [I{Element},] 52 @cvar matcher: A collection of I{lambda} for string matching. 53 @cvar specialprefixes: A dictionary of builtin-special prefixes. 54 """ 55 56 matcher = \ 57 { 58 'eq': lambda a,b: a == b, 59 'startswith' : lambda a,b: a.startswith(b), 60 'endswith' : lambda a,b: a.endswith(b), 61 'contains' : lambda a,b: b in a 62 } 63 64 specialprefixes = { Namespace.xmlns[0] : Namespace.xmlns[1] } 65 66 @classmethod
67 - def buildPath(self, parent, path):
68 """ 69 Build the specifed pat as a/b/c where missing intermediate nodes are built 70 automatically. 71 @param parent: A parent element on which the path is built. 72 @type parent: I{Element} 73 @param path: A simple path separated by (/). 74 @type path: basestring 75 @return: The leaf node of I{path}. 76 @rtype: L{Element} 77 """ 78 for tag in path.split('/'): 79 child = parent.getChild(tag) 80 if child is None: 81 child = Element(tag, parent) 82 parent = child 83 return child
84
85 - def __init__(self, name, parent=None, ns=None):
86 """ 87 @param name: The element's (tag) name. May cotain a prefix. 88 @type name: basestring 89 @param parent: An optional parent element. 90 @type parent: I{Element} 91 @param ns: An optional namespace 92 @type ns: (I{prefix}, I{name}) 93 """ 94 95 self.rename(name) 96 self.expns = None 97 self.nsprefixes = {} 98 self.attributes = [] 99 self.text = None 100 if parent is not None: 101 if isinstance(parent, Element): 102 self.parent = parent 103 else: 104 raise Exception('parent (%s) not-valid', parent.__class__.__name__) 105 else: 106 self.parent = None 107 self.children = [] 108 self.applyns(ns)
109
110 - def rename(self, name):
111 """ 112 Rename the element. 113 @param name: A new name for the element. 114 @type name: basestring 115 """ 116 if name is None: 117 raise Exception('name (%s) not-valid' % name) 118 else: 119 self.prefix, self.name = splitPrefix(name)
120
121 - def setPrefix(self, p, u=None):
122 """ 123 Set the element namespace prefix. 124 @param p: A new prefix for the element. 125 @type p: basestring 126 @param u: A namespace URI to be mapped to the prefix. 127 @type u: basestring 128 @return: self 129 @rtype: L{Element} 130 """ 131 self.prefix = p 132 if p is not None and u is not None: 133 self.addPrefix(p, u) 134 return self
135
136 - def qname(self):
137 """ 138 Get the B{fully} qualified name of this element 139 @return: The fully qualified name. 140 @rtype: basestring 141 """ 142 if self.prefix is None: 143 return self.name 144 else: 145 return '%s:%s' % (self.prefix, self.name)
146
147 - def getRoot(self):
148 """ 149 Get the root (top) node of the tree. 150 @return: The I{top} node of this tree. 151 @rtype: I{Element} 152 """ 153 if self.parent is None: 154 return self 155 else: 156 return self.parent.getRoot()
157
158 - def clone(self, parent=None):
159 """ 160 Deep clone of this element and children. 161 @param parent: An optional parent for the copied fragment. 162 @type parent: I{Element} 163 @return: A deep copy parented by I{parent} 164 @rtype: I{Element} 165 """ 166 root = Element(self.qname(), parent, self.namespace()) 167 for a in self.attributes: 168 root.append(a.clone(self)) 169 for c in self.children: 170 root.append(c.clone(self)) 171 for item in self.nsprefixes.items(): 172 root.addPrefix(item[0], item[1]) 173 return root
174
175 - def detach(self):
176 """ 177 Detach from parent. 178 @return: This element removed from its parent's 179 child list and I{parent}=I{None} 180 @rtype: L{Element} 181 """ 182 if self.parent is not None: 183 if self in self.parent.children: 184 self.parent.children.remove(self) 185 self.parent = None 186 return self
187
188 - def set(self, name, value):
189 """ 190 Set an attribute's value. 191 @param name: The name of the attribute. 192 @type name: basestring 193 @param value: The attribute value. 194 @type value: basestring 195 @see: __setitem__() 196 """ 197 attr = self.getAttribute(name) 198 if attr is None: 199 attr = Attribute(name, value) 200 self.append(attr) 201 else: 202 attr.setValue(value)
203
204 - def unset(self, name):
205 """ 206 Unset (remove) an attribute. 207 @param name: The attribute name. 208 @type name: str 209 @return: self 210 @rtype: L{Element} 211 """ 212 try: 213 attr = self.getAttribute(name) 214 self.attributes.remove(attr) 215 except: 216 pass 217 return self
218 219
220 - def get(self, name, ns=None, default=None):
221 """ 222 Get the value of an attribute by name. 223 @param name: The name of the attribute. 224 @type name: basestring 225 @param ns: The optional attribute's namespace. 226 @type ns: (I{prefix}, I{name}) 227 @param default: An optional value to be returned when either 228 the attribute does not exist of has not value. 229 @type default: basestring 230 @return: The attribute's value or I{default} 231 @rtype: basestring 232 @see: __getitem__() 233 """ 234 attr = self.getAttribute(name, ns) 235 if attr is None or attr.value is None: 236 return default 237 else: 238 return attr.getValue()
239
240 - def setText(self, value):
241 """ 242 Set the element's L{Text} content. 243 @param value: The element's text value. 244 @type value: basestring 245 @return: self 246 @rtype: I{Element} 247 """ 248 if isinstance(value, Text): 249 self.text = value 250 else: 251 self.text = Text(value) 252 return self
253
254 - def getText(self, default=None):
255 """ 256 Get the element's L{Text} content with optional default 257 @param default: A value to be returned when no text content exists. 258 @type default: basestring 259 @return: The text content, or I{default} 260 @rtype: L{Text} 261 """ 262 if self.hasText(): 263 return self.text 264 else: 265 return default
266
267 - def trim(self):
268 """ 269 Trim leading and trailing whitespace. 270 @return: self 271 @rtype: L{Element} 272 """ 273 if self.hasText(): 274 self.text = self.text.trim() 275 return self
276
277 - def hasText(self):
278 """ 279 Get whether the element has I{text} and that it is not an empty 280 (zero length) string. 281 @return: True when has I{text}. 282 @rtype: boolean 283 """ 284 return ( self.text is not None and len(self.text) )
285
286 - def namespace(self):
287 """ 288 Get the element's namespace. 289 @return: The element's namespace by resolving the prefix, the explicit 290 namespace or the inherited namespace. 291 @rtype: (I{prefix}, I{name}) 292 """ 293 if self.prefix is None: 294 return self.defaultNamespace() 295 else: 296 return self.resolvePrefix(self.prefix)
297
298 - def defaultNamespace(self):
299 """ 300 Get the default (unqualified namespace). 301 This is the expns of the first node (looking up the tree) 302 that has it set. 303 @return: The namespace of a node when not qualified. 304 @rtype: (I{prefix}, I{name}) 305 """ 306 p = self 307 while p is not None: 308 if p.expns is not None: 309 return (None, p.expns) 310 else: 311 p = p.parent 312 return Namespace.default
313
314 - def append(self, objects):
315 """ 316 Append the specified child based on whether it is an 317 element or an attrbuite. 318 @param objects: A (single|collection) of attribute(s) or element(s) 319 to be added as children. 320 @type objects: (L{Element}|L{Attribute}) 321 @return: self 322 @rtype: L{Element} 323 """ 324 if not isinstance(objects, (list, tuple)): 325 objects = (objects,) 326 for child in objects: 327 if isinstance(child, Element): 328 self.children.append(child) 329 child.parent = self 330 continue 331 if isinstance(child, Attribute): 332 self.attributes.append(child) 333 child.parent = self 334 continue 335 raise Exception('append %s not-valid' % child.__class__.__name__) 336 return self
337
338 - def insert(self, objects, index=0):
339 """ 340 Insert an L{Element} content at the specified index. 341 @param objects: A (single|collection) of attribute(s) or element(s) 342 to be added as children. 343 @type objects: (L{Element}|L{Attribute}) 344 @param index: The position in the list of children to insert. 345 @type index: int 346 @return: self 347 @rtype: L{Element} 348 """ 349 objects = (objects,) 350 for child in objects: 351 if isinstance(child, Element): 352 self.children.insert(index, child) 353 child.parent = self 354 else: 355 raise Exception('append %s not-valid' % child.__class__.__name__) 356 return self
357
358 - def remove(self, child):
359 """ 360 Remove the specified child element or attribute. 361 @param child: A child to remove. 362 @type child: L{Element}|L{Attribute} 363 @return: The detached I{child} when I{child} is an element, else None. 364 @rtype: L{Element}|None 365 """ 366 if isinstance(child, Element): 367 return child.detach() 368 if isinstance(child, Attribute): 369 self.attributes.remove(child) 370 return None
371
372 - def replaceChild(self, child, content):
373 """ 374 Replace I{child} with the specified I{content}. 375 @param child: A child element. 376 @type child: L{Element} 377 @param content: An element or collection of elements. 378 @type content: L{Element} or [L{Element},] 379 """ 380 if child not in self.children: 381 raise Exception('child not-found') 382 index = self.children.index(child) 383 self.remove(child) 384 if not isinstance(content, (list, tuple)): 385 content = (content,) 386 for node in content: 387 self.children.insert(index, node.detach()) 388 node.parent = self 389 index += 1
390
391 - def getAttribute(self, name, ns=None, default=None):
392 """ 393 Get an attribute by name and (optional) namespace 394 @param name: The name of a contained attribute (may contain prefix). 395 @type name: basestring 396 @param ns: An optional namespace 397 @type ns: (I{prefix}, I{name}) 398 @param default: Returned when attribute not-found. 399 @type default: L{Attribute} 400 @return: The requested attribute object. 401 @rtype: L{Attribute} 402 """ 403 if ns is None: 404 prefix, name = splitPrefix(name) 405 if prefix is None: 406 ns = None 407 else: 408 ns = self.resolvePrefix(prefix) 409 for a in self.attributes: 410 if a.match(name, ns): 411 return a 412 return default
413
414 - def getChild(self, name, ns=None, default=None):
415 """ 416 Get a child by (optional) name and/or (optional) namespace. 417 @param name: The name of a child element (may contain prefix). 418 @type name: basestring 419 @param ns: An optional namespace used to match the child. 420 @type ns: (I{prefix}, I{name}) 421 @param default: Returned when child not-found. 422 @type default: L{Element} 423 @return: The requested child, or I{default} when not-found. 424 @rtype: L{Element} 425 """ 426 if ns is None: 427 prefix, name = splitPrefix(name) 428 if prefix is None: 429 ns = None 430 else: 431 ns = self.resolvePrefix(prefix) 432 for c in self.children: 433 if c.match(name, ns): 434 return c 435 return default
436
437 - def childAtPath(self, path):
438 """ 439 Get a child at I{path} where I{path} is a (/) separated 440 list of element names that are expected to be children. 441 @param path: A (/) separated list of element names. 442 @type path: basestring 443 @return: The leaf node at the end of I{path} 444 @rtype: L{Element} 445 """ 446 result = None 447 node = self 448 for name in [p for p in path.split('/') if len(p) > 0]: 449 ns = None 450 prefix, name = splitPrefix(name) 451 if prefix is not None: 452 ns = node.resolvePrefix(prefix) 453 result = node.getChild(name, ns) 454 if result is None: 455 break; 456 else: 457 node = result 458 return result
459
460 - def childrenAtPath(self, path):
461 """ 462 Get a list of children at I{path} where I{path} is a (/) separated 463 list of element names that are expected to be children. 464 @param path: A (/) separated list of element names. 465 @type path: basestring 466 @return: The collection leaf nodes at the end of I{path} 467 @rtype: [L{Element},...] 468 """ 469 parts = [p for p in path.split('/') if len(p) > 0] 470 if len(parts) == 1: 471 result = self.getChildren(path) 472 else: 473 result = self.__childrenAtPath(parts) 474 return result
475
476 - def getChildren(self, name=None, ns=None):
477 """ 478 Get a list of children by (optional) name and/or (optional) namespace. 479 @param name: The name of a child element (may contain prefix). 480 @type name: basestring 481 @param ns: An optional namespace used to match the child. 482 @type ns: (I{prefix}, I{name}) 483 @return: The list of matching children. 484 @rtype: [L{Element},...] 485 """ 486 if ns is None: 487 if name is None: 488 return self.children 489 prefix, name = splitPrefix(name) 490 if prefix is None: 491 ns = None 492 else: 493 ns = self.resolvePrefix(prefix) 494 return [c for c in self.children if c.match(name, ns)]
495
496 - def detachChildren(self):
497 """ 498 Detach and return this element's children. 499 @return: The element's children (detached). 500 @rtype: [L{Element},...] 501 """ 502 detached = self.children 503 self.children = [] 504 for child in detached: 505 child.parent = None 506 return detached
507
508 - def resolvePrefix(self, prefix, default=Namespace.default):
509 """ 510 Resolve the specified prefix to a namespace. The I{nsprefixes} is 511 searched. If not found, it walks up the tree until either resolved or 512 the top of the tree is reached. Searching up the tree provides for 513 inherited mappings. 514 @param prefix: A namespace prefix to resolve. 515 @type prefix: basestring 516 @param default: An optional value to be returned when the prefix 517 cannot be resolved. 518 @type default: (I{prefix},I{URI}) 519 @return: The namespace that is mapped to I{prefix} in this context. 520 @rtype: (I{prefix},I{URI}) 521 """ 522 n = self 523 while n is not None: 524 if prefix in n.nsprefixes: 525 return (prefix, n.nsprefixes[prefix]) 526 if prefix in self.specialprefixes: 527 return (prefix, self.specialprefixes[prefix]) 528 n = n.parent 529 return default
530
531 - def addPrefix(self, p, u):
532 """ 533 Add or update a prefix mapping. 534 @param p: A prefix. 535 @type p: basestring 536 @param u: A namespace URI. 537 @type u: basestring 538 @return: self 539 @rtype: L{Element} 540 """ 541 self.nsprefixes[p] = u 542 return self
543
544 - def updatePrefix(self, p, u):
545 """ 546 Update (redefine) a prefix mapping for the branch. 547 @param p: A prefix. 548 @type p: basestring 549 @param u: A namespace URI. 550 @type u: basestring 551 @return: self 552 @rtype: L{Element} 553 @note: This method traverses down the entire branch! 554 """ 555 if p in self.nsprefixes: 556 self.nsprefixes[p] = u 557 for c in self.children: 558 c.updatePrefix(p, u) 559 return self
560
561 - def clearPrefix(self, prefix):
562 """ 563 Clear the specified prefix from the prefix mappings. 564 @param prefix: A prefix to clear. 565 @type prefix: basestring 566 @return: self 567 @rtype: L{Element} 568 """ 569 if prefix in self.nsprefixes: 570 del self.nsprefixes[prefix] 571 return self
572
573 - def findPrefix(self, uri, default=None):
574 """ 575 Find the first prefix that has been mapped to a namespace URI. 576 The local mapping is searched, then it walks up the tree until 577 it reaches the top or finds a match. 578 @param uri: A namespace URI. 579 @type uri: basestring 580 @param default: A default prefix when not found. 581 @type default: basestring 582 @return: A mapped prefix. 583 @rtype: basestring 584 """ 585 for item in self.nsprefixes.items(): 586 if item[1] == uri: 587 prefix = item[0] 588 return prefix 589 for item in self.specialprefixes.items(): 590 if item[1] == uri: 591 prefix = item[0] 592 return prefix 593 if self.parent is not None: 594 return self.parent.findPrefix(uri, default) 595 else: 596 return default
597
598 - def findPrefixes(self, uri, match='eq'):
599 """ 600 Find all prefixes that has been mapped to a namespace URI. 601 The local mapping is searched, then it walks up the tree until 602 it reaches the top collecting all matches. 603 @param uri: A namespace URI. 604 @type uri: basestring 605 @param match: A matching function L{Element.matcher}. 606 @type match: basestring 607 @return: A list of mapped prefixes. 608 @rtype: [basestring,...] 609 """ 610 result = [] 611 for item in self.nsprefixes.items(): 612 if self.matcher[match](item[1], uri): 613 prefix = item[0] 614 result.append(prefix) 615 for item in self.specialprefixes.items(): 616 if self.matcher[match](item[1], uri): 617 prefix = item[0] 618 result.append(prefix) 619 if self.parent is not None: 620 result += self.parent.findPrefixes(uri, match) 621 return result
622
623 - def promotePrefixes(self):
624 """ 625 Push prefix declarations up the tree as far as possible. Prefix 626 mapping are pushed to its parent unless the parent has the 627 prefix mapped to another URI or the parent has the prefix. 628 This is propagated up the tree until the top is reached. 629 @return: self 630 @rtype: L{Element} 631 """ 632 for c in self.children: 633 c.promotePrefixes() 634 if self.parent is None: 635 return 636 for p,u in self.nsprefixes.items(): 637 if p in self.parent.nsprefixes: 638 pu = self.parent.nsprefixes[p] 639 if pu == u: 640 del self.nsprefixes[p] 641 continue 642 if p != self.parent.prefix: 643 self.parent.nsprefixes[p] = u 644 del self.nsprefixes[p] 645 return self
646
647 - def refitPrefixes(self):
648 """ 649 Refit namespace qualification by replacing prefixes 650 with explicit namespaces. Also purges prefix mapping table. 651 @return: self 652 @rtype: L{Element} 653 """ 654 for c in self.children: 655 c.refitPrefixes() 656 if self.prefix is not None: 657 ns = self.resolvePrefix(self.prefix) 658 if ns[1] is not None: 659 self.expns = ns[1] 660 self.prefix = None 661 self.nsprefixes = {} 662 return self
663
664 - def normalizePrefixes(self):
665 """ 666 Normalize the namespace prefixes. 667 This generates unique prefixes for all namespaces. Then retrofits all 668 prefixes and prefix mappings. Further, it will retrofix attribute values 669 that have values containing (:). 670 @return: self 671 @rtype: L{Element} 672 """ 673 PrefixNormalizer.apply(self) 674 return self
675
676 - def isempty(self, content=True):
677 """ 678 Get whether the element has no children. 679 @param content: Test content (children & text) only. 680 @type content: boolean 681 @return: True when element has not children. 682 @rtype: boolean 683 """ 684 noattrs = not len(self.attributes) 685 nochildren = not len(self.children) 686 notext = ( self.text is None ) 687 nocontent = ( nochildren and notext ) 688 if content: 689 return nocontent 690 else: 691 return ( nocontent and noattrs )
692 693
694 - def isnil(self):
695 """ 696 Get whether the element is I{nil} as defined by having 697 an attribute in the I{xsi:nil="true"} 698 @return: True if I{nil}, else False 699 @rtype: boolean 700 """ 701 nilattr = self.getAttribute('nil', ns=Namespace.xsins) 702 if nilattr is None: 703 return False 704 else: 705 return ( nilattr.getValue().lower() == 'true' )
706
707 - def setnil(self, flag=True):
708 """ 709 Set this node to I{nil} as defined by having an 710 attribute I{xsi:nil}=I{flag}. 711 @param flag: A flag inidcating how I{xsi:nil} will be set. 712 @type flag: boolean 713 @return: self 714 @rtype: L{Element} 715 """ 716 p, u = Namespace.xsins 717 name = ':'.join((p, 'nil')) 718 self.set(name, str(flag).lower()) 719 self.addPrefix(p, u) 720 if flag: 721 self.text = None 722 return self
723
724 - def applyns(self, ns):
725 """ 726 Apply the namespace to this node. If the prefix is I{None} then 727 this element's explicit namespace I{expns} is set to the 728 URI defined by I{ns}. Otherwise, the I{ns} is simply mapped. 729 @param ns: A namespace. 730 @type ns: (I{prefix},I{URI}) 731 """ 732 if ns is None: 733 return 734 if not isinstance(ns, (tuple,list)): 735 raise Exception('namespace must be tuple') 736 if ns[0] is None: 737 self.expns = ns[1] 738 else: 739 self.prefix = ns[0] 740 self.nsprefixes[ns[0]] = ns[1]
741
742 - def str(self, indent=0):
743 """ 744 Get a string representation of this XML fragment. 745 @param indent: The indent to be used in formatting the output. 746 @type indent: int 747 @return: A I{pretty} string. 748 @rtype: basestring 749 """ 750 tab = '%*s'%(indent*3,'') 751 result = [] 752 result.append('%s<%s' % (tab, self.qname())) 753 result.append(self.nsdeclarations()) 754 for a in [unicode(a) for a in self.attributes]: 755 result.append(' %s' % a) 756 if self.isempty(): 757 result.append('/>') 758 return ''.join(result) 759 result.append('>') 760 if self.hasText(): 761 result.append(self.text.escape()) 762 for c in self.children: 763 result.append('\n') 764 result.append(c.str(indent+1)) 765 if len(self.children): 766 result.append('\n%s' % tab) 767 result.append('</%s>' % self.qname()) 768 result = ''.join(result) 769 return result
770
771 - def plain(self):
772 """ 773 Get a string representation of this XML fragment. 774 @return: A I{plain} string. 775 @rtype: basestring 776 """ 777 result = [] 778 result.append('<%s' % self.qname()) 779 result.append(self.nsdeclarations()) 780 for a in [unicode(a) for a in self.attributes]: 781 result.append(' %s' % a) 782 if self.isempty(): 783 result.append('/>') 784 return ''.join(result) 785 result.append('>') 786 if self.hasText(): 787 result.append(self.text.escape()) 788 for c in self.children: 789 result.append(c.plain()) 790 result.append('</%s>' % self.qname()) 791 result = ''.join(result) 792 return result
793
794 - def nsdeclarations(self):
795 """ 796 Get a string representation for all namespace declarations 797 as xmlns="" and xmlns:p="". 798 @return: A separated list of declarations. 799 @rtype: basestring 800 """ 801 s = [] 802 myns = (None, self.expns) 803 if self.parent is None: 804 pns = Namespace.default 805 else: 806 pns = (None, self.parent.expns) 807 if myns[1] != pns[1]: 808 if self.expns is not None: 809 d = ' xmlns="%s"' % self.expns 810 s.append(d) 811 for item in self.nsprefixes.items(): 812 (p,u) = item 813 if self.parent is not None: 814 ns = self.parent.resolvePrefix(p) 815 if ns[1] == u: continue 816 d = ' xmlns:%s="%s"' % (p, u) 817 s.append(d) 818 return ''.join(s)
819
820 - def match(self, name=None, ns=None):
821 """ 822 Match by (optional) name and/or (optional) namespace. 823 @param name: The optional element tag name. 824 @type name: str 825 @param ns: An optional namespace. 826 @type ns: (I{prefix}, I{name}) 827 @return: True if matched. 828 @rtype: boolean 829 """ 830 if name is None: 831 byname = True 832 else: 833 byname = ( self.name == name ) 834 if ns is None: 835 byns = True 836 else: 837 byns = ( self.namespace()[1] == ns[1] ) 838 return ( byname and byns )
839
840 - def branch(self):
841 """ 842 Get a flattened representation of the branch. 843 @return: A flat list of nodes. 844 @rtype: [L{Element},..] 845 """ 846 branch = [self] 847 for c in self.children: 848 branch += c.branch() 849 return branch
850
851 - def ancestors(self):
852 """ 853 Get a list of ancestors. 854 @return: A list of ancestors. 855 @rtype: [L{Element},..] 856 """ 857 ancestors = [] 858 p = self.parent 859 while p is not None: 860 ancestors.append(p) 861 p = p.parent 862 return ancestors
863
864 - def walk(self, visitor):
865 """ 866 Walk the branch and call the visitor function 867 on each node. 868 @param visitor: A function. 869 @return: self 870 @rtype: L{Element} 871 """ 872 visitor(self) 873 for c in self.children: 874 c.walk(visitor) 875 return self
876
877 - def prune(self):
878 """ 879 Prune the branch of empty nodes. 880 """ 881 pruned = [] 882 for c in self.children: 883 c.prune() 884 if c.isempty(False): 885 pruned.append(c) 886 for p in pruned: 887 self.children.remove(p)
888 889
890 - def __childrenAtPath(self, parts):
891 result = [] 892 node = self 893 last = len(parts)-1 894 ancestors = parts[:last] 895 leaf = parts[last] 896 for name in ancestors: 897 ns = None 898 prefix, name = splitPrefix(name) 899 if prefix is not None: 900 ns = node.resolvePrefix(prefix) 901 child = node.getChild(name, ns) 902 if child is None: 903 break 904 else: 905 node = child 906 if child is not None: 907 ns = None 908 prefix, leaf = splitPrefix(leaf) 909 if prefix is not None: 910 ns = node.resolvePrefix(prefix) 911 result = child.getChildren(leaf) 912 return result
913
914 - def __len__(self):
915 return len(self.children)
916
917 - def __getitem__(self, index):
918 if isinstance(index, basestring): 919 return self.get(index) 920 else: 921 if index < len(self.children): 922 return self.children[index] 923 else: 924 return None
925
926 - def __setitem__(self, index, value):
927 if isinstance(index, basestring): 928 self.set(index, value) 929 else: 930 if index < len(self.children) and \ 931 isinstance(value, Element): 932 self.children.insert(index, value)
933
934 - def __eq__(self, rhs):
935 return rhs is not None and \ 936 isinstance(rhs, Element) and \ 937 self.name == rhs.name and \ 938 self.namespace()[1] == rhs.namespace()[1]
939
940 - def __repr__(self):
941 return \ 942 'Element (prefix=%s, name=%s)' % (self.prefix, self.name)
943
944 - def __str__(self):
945 return unicode(self).encode('utf-8')
946
947 - def __unicode__(self):
948 return self.str()
949
950 - def __iter__(self):
951 return NodeIterator(self)
952
953 954 -class NodeIterator:
955 """ 956 The L{Element} child node iterator. 957 @ivar pos: The current position 958 @type pos: int 959 @ivar children: A list of a child nodes. 960 @type children: [L{Element},..] 961 """ 962
963 - def __init__(self, parent):
964 """ 965 @param parent: An element to iterate. 966 @type parent: L{Element} 967 """ 968 self.pos = 0 969 self.children = parent.children
970
971 - def next(self):
972 """ 973 Get the next child. 974 @return: The next child. 975 @rtype: L{Element} 976 @raise StopIterator: At the end. 977 """ 978 try: 979 child = self.children[self.pos] 980 self.pos += 1 981 return child 982 except: 983 raise StopIteration()
984
985 986 -class PrefixNormalizer:
987 """ 988 The prefix normalizer provides namespace prefix normalization. 989 @ivar node: A node to normalize. 990 @type node: L{Element} 991 @ivar branch: The nodes flattened branch. 992 @type branch: [L{Element},..] 993 @ivar namespaces: A unique list of namespaces (URI). 994 @type namespaces: [str,] 995 @ivar prefixes: A reverse dict of prefixes. 996 @type prefixes: {u, p} 997 """ 998 999 @classmethod
1000 - def apply(cls, node):
1001 """ 1002 Normalize the specified node. 1003 @param node: A node to normalize. 1004 @type node: L{Element} 1005 @return: The normalized node. 1006 @rtype: L{Element} 1007 """ 1008 pn = PrefixNormalizer(node) 1009 return pn.refit()
1010
1011 - def __init__(self, node):
1012 """ 1013 @param node: A node to normalize. 1014 @type node: L{Element} 1015 """ 1016 self.node = node 1017 self.branch = node.branch() 1018 self.namespaces = self.getNamespaces() 1019 self.prefixes = self.genPrefixes()
1020
1021 - def getNamespaces(self):
1022 """ 1023 Get the I{unique} set of namespaces referenced in the branch. 1024 @return: A set of namespaces. 1025 @rtype: set 1026 """ 1027 s = set() 1028 for n in self.branch + self.node.ancestors(): 1029 if self.permit(n.expns): 1030 s.add(n.expns) 1031 s = s.union(self.pset(n)) 1032 return s
1033
1034 - def pset(self, n):
1035 """ 1036 Convert the nodes nsprefixes into a set. 1037 @param n: A node. 1038 @type n: L{Element} 1039 @return: A set of namespaces. 1040 @rtype: set 1041 """ 1042 s = set() 1043 for ns in n.nsprefixes.items(): 1044 if self.permit(ns): 1045 s.add(ns[1]) 1046 return s
1047
1048 - def genPrefixes(self):
1049 """ 1050 Generate a I{reverse} mapping of unique prefixes for all namespaces. 1051 @return: A referse dict of prefixes. 1052 @rtype: {u, p} 1053 """ 1054 prefixes = {} 1055 n = 0 1056 for u in self.namespaces: 1057 p = 'ns%d' % n 1058 prefixes[u] = p 1059 n += 1 1060 return prefixes
1061
1062 - def refit(self):
1063 """ 1064 Refit (normalize) the prefixes in the node. 1065 """ 1066 self.refitNodes() 1067 self.refitMappings()
1068
1069 - def refitNodes(self):
1070 """ 1071 Refit (normalize) all of the nodes in the branch. 1072 """ 1073 for n in self.branch: 1074 if n.prefix is not None: 1075 ns = n.namespace() 1076 if self.permit(ns): 1077 n.prefix = self.prefixes[ns[1]] 1078 self.refitAttrs(n)
1079
1080 - def refitAttrs(self, n):
1081 """ 1082 Refit (normalize) all of the attributes in the node. 1083 @param n: A node. 1084 @type n: L{Element} 1085 """ 1086 for a in n.attributes: 1087 self.refitAddr(a)
1088
1089 - def refitAddr(self, a):
1090 """ 1091 Refit (normalize) the attribute. 1092 @param a: An attribute. 1093 @type a: L{Attribute} 1094 """ 1095 if a.prefix is not None: 1096 ns = a.namespace() 1097 if self.permit(ns): 1098 a.prefix = self.prefixes[ns[1]] 1099 self.refitValue(a)
1100
1101 - def refitValue(self, a):
1102 """ 1103 Refit (normalize) the attribute's value. 1104 @param a: An attribute. 1105 @type a: L{Attribute} 1106 """ 1107 p,name = splitPrefix(a.getValue()) 1108 if p is None: return 1109 ns = a.resolvePrefix(p) 1110 if self.permit(ns): 1111 u = ns[1] 1112 p = self.prefixes[u] 1113 a.setValue(':'.join((p, name)))
1114
1115 - def refitMappings(self):
1116 """ 1117 Refit (normalize) all of the nsprefix mappings. 1118 """ 1119 for n in self.branch: 1120 n.nsprefixes = {} 1121 n = self.node 1122 for u, p in self.prefixes.items(): 1123 n.addPrefix(p, u)
1124
1125 - def permit(self, ns):
1126 """ 1127 Get whether the I{ns} is to be normalized. 1128 @param ns: A namespace. 1129 @type ns: (p,u) 1130 @return: True if to be included. 1131 @rtype: boolean 1132 """ 1133 return not self.skip(ns)
1134
1135 - def skip(self, ns):
1136 """ 1137 Get whether the I{ns} is to B{not} be normalized. 1138 @param ns: A namespace. 1139 @type ns: (p,u) 1140 @return: True if to be skipped. 1141 @rtype: boolean 1142 """ 1143 return ns is None or \ 1144 ( ns == Namespace.default ) or \ 1145 ( ns == Namespace.xsdns ) or \ 1146 ( ns == Namespace.xsins) or \ 1147 ( ns == Namespace.xmlns )
1148