Changeset 428
- Timestamp:
- 01/27/03 16:42:50 (6 years ago)
- Files:
-
- trunk/RBFoundation/RBFoundation/XMLNode.py (modified) (13 diffs)
- trunk/RBFoundation/RBFoundation/XSDConverter.py (deleted)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/RBFoundation/RBFoundation/XMLNode.py
r418 r428 24 24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 25 26 from __future__ import generators 27 import sys 26 28 from xml.sax.saxutils import quoteattr as xmlquoteattr 27 29 from xml.sax.saxutils import escape as xmlescape 30 from types import SliceType as _SliceType 31 from types import NoneType as _NoneType 28 32 29 33 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ … … 31 35 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 36 33 try: basestring 34 except NameError: basestring = (str, unicode) 37 if sys.version_info < (2,2,3): 38 basestring = (str, unicode) 39 40 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 41 42 class matchall(object): 43 def __eq__(self, other): 44 return True 45 def __ne__(self, other): 46 return not self.__eq__(other) 47 _any = matchall() 48 49 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 50 51 class matchobj(object): 52 def __init__(self, testcall): 53 self.testcall = testcall 54 def __eq__(self, other): 55 return self.testcall(other) and True or False 56 def __ne__(self, other): 57 return not self.__eq__(other) 35 58 36 59 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 60 38 61 class xmlnode(object): 62 """Simple class to build valid XML. 63 Also has some basic access, query, and iteration methods. 64 65 >>> node = xmlnode('mynode', 'mynamespace') 66 >>> node.attrs['aname'] = 'avalue' 67 >>> node.aname 68 'avalue' 69 >>> node += "\n" 70 >>> node += "some cdata text \n" 71 >>> node += "some more cdata text \n" 72 >>> node += ('another_node', ) 73 >>> node += "\n" 74 >>> node += ('third', 'namespace-for-third') 75 >>> node += "\n" 76 >>> node += ('forth', 'namespace-for-forth', 'four') 77 >>> node += "\n" 78 >>> print node 79 <mynode xmlns="mynamespace" aname="avalue"> 80 some cdata text 81 some more cdata text 82 <another_node/> 83 <third xmlns="namespace-for-third"/> 84 <four:forth xmlns:four="namespace-for-forth"/> 85 </mynode> 86 """ 87 39 88 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 40 89 #~ Constants / Variables / Etc. … … 56 105 57 106 def __getattribute__(self, name): 107 """Returns self.attrs[name] when possible. Use explicit self.attrs[name] for more uniform access.""" 58 108 try: 59 109 return object.__getattribute__(self, name) … … 64 114 65 115 def __setattr__(self, name, value): 116 """Sets self.attrs[name] = value when possible. Use explicit self.attrs[name] for more uniform access.""" 66 117 try: 67 118 # This works because of the __slots__ definition 68 119 object.__setattr__(self, name, value) 69 120 except AttributeError: 70 self.addattr((name,value)) 71 72 def __getitem__(self, *args, **kw): 73 return self.elems.__getitem__(*args, **kw) 74 def __setitem__(self, *args, **kw): 75 return self.elems.__setitem__(*args, **kw) 76 def __delitem__(self, *args, **kw): 77 return self.elems.__delitem__(*args, **kw) 121 self.addattr((name,str(value))) 122 123 def __getitem__(self, key, *args, **kw): 124 """Returns a list of matching child elements of xmlnode. See listelems.""" 125 if isinstance(key, (int, long, _SliceType)): 126 return self.elems.__getitem__(key, *args, **kw) 127 else: 128 return self.listelems(key, *args, **kw) 129 def __setitem__(self, key, *args, **kw): 130 """Sets child element at self.elem[key] = value.""" 131 if isinstance(key, (int, long, _SliceType)): 132 return self.elems.__setitem__(*args, **kw) 133 else: 134 raise TypeError, "Cannot set node elemenets with non integer key item operations" 135 def __delitem__(self, key, *args, **kw): 136 """Removes all matching child elements of xmlnode. See delelems.""" 137 if isinstance(key, (int, long, _SliceType)): 138 return self.elems.__delitem__(*args, **kw) 139 else: 140 self.delelems(key, *args, **kw) 141 142 def __contains__(self, key, *args, **kw): 143 """Returns True if key is a child element of xmlnode. See haselem.""" 144 if isinstance(key, (int, long, _SliceType)): 145 return self.elems.__contains__(key, *args, **kw) 146 else: 147 return self.haselem(key, *args, **kw) 78 148 79 149 def __iadd__(self, other): 80 self.addelement(other) 150 """Adds an element to xmlnode. See addelem.""" 151 self.addelem(other) 81 152 return self 82 153 154 def __iter__(self): 155 """Returns an iterator of child elements""" 156 return iter(self.elems) 157 158 def __str__(self): 159 """Returns xmlnode as a string in XML form""" 160 return str(self.toXML()) 161 83 162 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 84 163 #~ Public Methods … … 86 165 87 166 def addattr(self, *args, **kw): 167 """Adds attributes to xmlnode.""" 88 168 if args: self.attrs.update(dict(args)) 89 169 if kw: self.attrs.update(kw) 90 170 91 def addtext(self, text): 171 def adddata(self, text): 172 """Adds a child cdata to xmlnode.""" 92 173 self.elems.append(text) 93 174 return text 175 def addtext(self, *args, **kw): 176 """See adddata.""" 177 return self.adddata(*args, **kw) 178 def write(self, data): 179 """For use in conjunction with file-like uses. 180 181 >>> node = xmlnode('mynode', 'mynamespace') 182 >>> print >> node 183 >>> print >> node, 'some cdata' 184 >>> node.toxml() 185 '<mynode xmlns="mynamespace" softspace="0">\\nsome cdata\\n</mynode>' 186 """ 187 self.adddata(data) 94 188 95 189 def addnode(self, *args, **kw): 190 """Adds a child node to xmlnode.""" 96 191 nodebuilder = self.nodebuilder or self.__class__ 97 192 result = nodebuilder(*args, **kw) … … 99 194 return result 100 195 101 def addelement(self, elem): 196 def addelem(self, elem): 197 """Adds a child element to xmlnode. 198 Elem is considered cdata if it is of string type, 199 or a node, otherwise.""" 102 200 if isinstance(elem, basestring): 103 return self.add text(elem)201 return self.adddata(elem) 104 202 else: return self.addnode(*elem) 105 203 106 def set namespace(self, prefix, namespace):204 def setxmlns(self, prefix, namespace): 107 205 if namespace is None: 108 206 try: del self.namespaces[prefix or ''] … … 110 208 else: 111 209 self.namespaces[prefix or ''] = namespace 112 setns = setnamespace # short alias 210 211 #~ iteration over elements ~~~~~~~~~~~~~~~~~~~~~~~~~~ 212 213 def enumdata(self, match=None): 214 """Returns a generator to iterate through the matching data indices in xmlnode""" 215 if not match: match = _any 216 elif callable(match): match = matchobj(match) 217 idx = 0 218 for each in self.elems: 219 if isinstance(each, basestring): 220 if each == match: 221 yield idx 222 idx += 1 223 224 def iterdata(self, match=None): 225 """Returns a generator to iterate through the matching data in xmlnode""" 226 if not match: match = _any 227 elif callable(match): match = matchobj(match) 228 for each in self.elems: 229 if isinstance(each, basestring): 230 if each == match: 231 yield each 232 233 def listdata(self, *args, **kw): 234 """Returns a list of matching data in xmlnode""" 235 return [x for x in self.iterdata(*args, **kw)] 236 237 def deldata(self, *args, **kw): 238 dellist = [x for x in self.enumdata(*args, **kw)] 239 for idx in dellist: 240 del self.elems[idx] 241 242 def hasdata(self, *args, **kw): 243 """Returns True if data is in xmlnode""" 244 try: 245 self.iterdata(*args, **kw).next() 246 return True 247 except StopIteration: 248 return False 249 250 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 251 252 def enumnodes(self, node=_any, namespace=_any, prefix=_any): 253 """Returns a generator to iterate through the matching child node indicies of xmlnode""" 254 idx = 0 255 for each in self.elems: 256 if not isinstance(each, basestring): 257 if node == each.node and namespace == each.namespace and prefix == each.prefix: 258 yield idx 259 idx += 1 260 261 def iternodes(self, node=_any, namespace=_any, prefix=_any): 262 """Returns a generator to iterate through the matching child nodes of xmlnode""" 263 for each in self.elems: 264 if not isinstance(each, basestring): 265 if node == each.node and namespace == each.namespace and prefix == each.prefix: 266 yield each 267 268 def listnodes(self, *args, **kw): 269 """Returns a list of matching child nodes of xmlnode""" 270 return [x for x in self.iternodes(*args, **kw)] 271 272 def delnodes(self, *args, **kw): 273 """Removes all matching child nodes of xmlnode""" 274 dellist = [x for x in self.enumnodes(*args, **kw)] 275 for idx in dellist: 276 del self.elems[idx] 277 278 def hasnode(self, *args, **kw): 279 """Returns True if elem is a child node of the xmlnode""" 280 try: 281 self.iternodes(*args, **kw).next() 282 return True 283 except StopIteration: 284 return False 285 286 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 287 288 def enumelems(self, key=None, **kw): 289 """Returns a generator to iterate through the matching child element indicies of xmlnode""" 290 if isinstance(key, tuple): 291 return self.enumnodes(*key, **kw) 292 elif isinstance(key, _NoneType): 293 return xrange(0, len(self.elems)) 294 else: 295 return self.enumdata(key, **kw) 296 297 def iterelems(self, key=None, **kw): 298 """Returns a generator to iterate through the matching child elements of xmlnode""" 299 if isinstance(key, tuple): 300 return self.iternodes(*key, **kw) 301 elif isinstance(key, _NoneType): 302 return iter(self.elems) 303 else: 304 return self.iterdata(key, **kw) 305 306 def listelems(self, *args, **kw): 307 """Returns a list of matching child elements of xmlnode""" 308 return [x for x in self.iterelems(*args, **kw)] 309 310 def delelems(self, key, **kw): 311 """Removes all matching child elements of xmlnode""" 312 if isinstance(key, tuple): 313 self.delnodes(*key, **kw) 314 elif isinstance(key, _NoneType): 315 del self.elems[:] 316 else: 317 self.deldata(key, **kw) 318 319 def haselem(self, elem, *args, **kw): 320 """Returns True if elem is a child element of the xmlnode""" 321 try: 322 if isinstance(elem, tuple): 323 return self.hasnode(*elem, **kw) 324 elif isinstance(elem, _NoneType): 325 return False 326 else: 327 return self.hasdata(*elem, **kw) 328 except StopIteration: 329 return False 113 330 114 331 #~ namespace property ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 115 332 116 333 def _getnamespace(self): 334 """Returns the namespace of the xmlnode""" 117 335 return self.namespaces.get(self.prefix or '', None) 118 336 def _setnamespace(self, namespace): 337 """Sets the namespace of the xmlnode""" 119 338 if isinstance(namespace, tuple): 120 339 if len(namespace) == 1: … … 125 344 self.namespaces[self.prefix or ''] = namespace 126 345 def _delnamespace(self): 346 """Removes the namespace of the xmlnode""" 127 347 try: del self.namespaces[self.prefix or ''] 128 348 except KeyError: pass … … 131 351 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 132 352 133 def toXML(self, pretty=False, level=0, indent=' '): 353 def toxml(self, pretty=False, level=0, indent=' ', newline='\n'): 354 """Converts the xmlnode to valid XML.""" 134 355 result = ['<'] 135 356 if self.prefix: … … 148 369 if self.elems: 149 370 result.append('>') 150 result.extend(self._elems ToXML(pretty, level+1, indent))151 if pretty: result.append( '\n'+ indent * level)371 result.extend(self._elemstoxml(pretty, level+1, indent, newline)) 372 if pretty: result.append(newline + indent * level) 152 373 result.append('</%s>' % nodename) 153 374 else: 154 375 result.append('/>') 155 376 return ''.join(result) 156 157 def _elemsToXML(self, pretty, level, indent): 158 if pretty: prettyindent = '\n' + indent * level 377 def toXML(self, *args, **kw): 378 """See toxml.""" 379 return self.toxml(*args, **kw) 380 def _toXML(self, *args, **kw): 381 """See toxml.""" 382 return self.toxml(*args, **kw) 383 384 def _elemstoxml(self, pretty, level, indent, newline): 385 """Converts child elements of xmlnode to valid XML.""" 386 if pretty: prettyindent = newline + indent * level 159 387 result = [] 160 388 for elem in self.elems: … … 162 390 if isinstance(elem, basestring): 163 391 result.append(xmlescape(elem)) 164 else: result.append(elem.toXML(pretty, level, indent ))392 else: result.append(elem.toXML(pretty, level, indent, newline)) 165 393 return result 166 394 … … 171 399 else: 172 400 class NodeXML(xmlnode, XMLBuilder.XMLBuilderObjectBase): 401 """An adaptor to bridge between XMLBuilderObjectBase class and xmlnode""" 173 402 def __init__(self, owner, parent, node, attributes, namespacemap): 174 403 xmlnode.__init__(self, node[1], node[0], namespacemap.get(node[0], '')) 404 self.addattr(attributes) 405 for xmlns, prefix in namespacemap.iteritems(): 406 self.namespaces[prefix] = xmlns 175 407 def _addElement(self, node, obj): 176 408 self.elems.append(obj) … … 199 431 x += 'Some cdata' 200 432 x += 'subelem', 433 x += 'More data' 434 x += ('element',) 201 435 x += 'anotherelem', 'SubNamespace' 202 436 anotherelem = x[-1]
