Package bridge
[hide private]
[frames] | no frames]

Source Code for Package bridge

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  __version__ = "0.2.0" 
  5  __authors__ = ["Sylvain Hellegouarch (sh@defuze.org)"] 
  6  __contributors__ = ['David Turner'] 
  7  __date__ = "2006/12/08" 
  8  __copyright__ = """ 
  9  Copyright (c) 2006 Sylvain Hellegouarch 
 10  All rights reserved. 
 11  """ 
 12  __license__ = """ 
 13  Redistribution and use in source and binary forms, with or without modification,  
 14  are permitted provided that the following conditions are met: 
 15    
 16       * Redistributions of source code must retain the above copyright notice,  
 17         this list of conditions and the following disclaimer. 
 18       * Redistributions in binary form must reproduce the above copyright notice,  
 19         this list of conditions and the following disclaimer in the documentation  
 20         and/or other materials provided with the distribution. 
 21       * Neither the name of Sylvain Hellegouarch nor the names of his contributors  
 22         may be used to endorse or promote products derived from this software  
 23         without specific prior written permission. 
 24    
 25  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND  
 26  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
 27  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
 28  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE  
 29  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
 30  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  
 31  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER  
 32  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,  
 33  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  
 34  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 35  """ 
 36   
 37  ENCODING = 'UTF-8' 
 38  DUMMY_URI = u'http://dummy.com' 
 39   
 40  import bridge.parser.bridge_default 
 41  from bridge.filter import fetch_child, fetch_children 
 42   
 43  from bridge.common import  XML_NS, XMLNS_NS  
 44   
 45  __all__ = ['Attribute', 'Element', 'PI', 'Comment', 'Document'] 
 46   
47 -class PI(object):
48 - def __init__(self, target, data, parent=None):
49 self.target = target 50 self.data = data 51 self.xml_parent = parent 52 53 if self.xml_parent: 54 self.xml_parent.xml_children.append(self)
55
56 -class Comment(object):
57 - def __init__(self, data, parent=None):
58 self.data = data 59 self.xml_parent = parent 60 61 if self.xml_parent: 62 self.xml_parent.xml_children.append(self)
63
64 -class Attribute(object):
65 """ 66 Maps the attribute of an XML element to a simple Python object. 67 """ 68 69 encoding = ENCODING 70 as_attribute_of_element = None 71
72 - def __init__(self, name=None, value=None, prefix=None, namespace=None, parent=None):
73 """ 74 Maps the attribute of an XML element to a simple Python object. 75 76 Keyword arguments: 77 name -- Name of the attribute 78 value -- content of the attribute 79 prefix -- XML prefix of the element 80 namespace -- XML namespace defining the prefix 81 parent -- element which this attribute belongs to 82 """ 83 if value and not isinstance(value, unicode): 84 raise TypeError, "Attribute's value must be an unicode object or None" 85 86 self.xml_parent = parent 87 self.xml_name = name 88 self.xml_text = value 89 self.xml_prefix = prefix 90 self.xml_ns = namespace 91 92 self.as_attribute_of_element = {} 93 if self.xml_parent and self.xml_parent.xml_root.as_attribute_of_element: 94 self.as_attribute_of_element.update(self.xml_parent.xml_root.as_attribute_of_element) 95 elif isinstance(Attribute.as_attribute_of_element, dict): 96 self.as_attribute_of_element.update(Attribute.as_attribute_of_element) 97 98 if self.xml_parent: 99 self.xml_parent.xml_attributes.append(self) 100 101 attrs = self.as_attribute_of_element.get(self.xml_ns, []) 102 if self.xml_name in attrs: 103 name = self.xml_name.replace('-', '_') 104 name = name.replace('.', '_') 105 if not hasattr(self.xml_parent, name): 106 setattr(self.xml_parent, name, self.xml_text)
107
108 - def __unicode__(self):
109 if self.xml_text: 110 return self.xml_text 111 return unicode(self.xml_text)
112
113 - def __str__(self):
114 if self.xml_text: 115 return self.xml_text.encode(self.encoding) 116 return str(self.xml_text)
117
118 - def __repr__(self):
119 value = self.xml_text or '' 120 return '%s="%s" attribute at %s' % (self.xml_name, value, hex(id(self)))
121
122 -class Element(object):
123 """ 124 Maps an XML element to a Python object. 125 """ 126 127 parser = bridge.parser.bridge_default.Parser 128 encoding = ENCODING 129 as_list = None 130 as_attribute = None 131
132 - def __init__(self, name=None, content=None, attributes=None, prefix=None, namespace=None, parent=None):
133 """ 134 Maps an XML element to a Python object. 135 136 Keyword arguments: 137 name -- Name of the XML element 138 content -- Content of the element 139 attributes -- dictionary of the form {local_name: value} 140 prefix -- XML prefix of the element 141 namespace -- XML namespace attached to that element 142 parent -- Parent element of this element. 143 144 If 'parent' is not None, 'self' will be added to the parent.xml_children 145 146 If 'Element.as_list' is set and if (name, namespace) belongs to it 147 then we will add a list to parent with the name of the element 148 149 If 'Element.as_attribute' is set and if (name, namespace) belongs to it 150 then we will add an attribute to parent with the name of the element 151 """ 152 if content and not isinstance(content, unicode): 153 raise TypeError, "Element's content must be an unicode object or None" 154 155 self._root = None 156 self.xml_parent = parent 157 self.xml_prefix = prefix 158 self.xml_ns = namespace 159 self.xml_name = name 160 self.xml_text = content 161 self.xml_children = [] 162 self.xml_attributes = [] 163 164 if self.xml_root is None: 165 return 166 167 self.as_attribute = {} 168 if self.xml_root.as_attribute: 169 self.as_attribute.update(self.xml_root.as_attribute) 170 elif isinstance(Element.as_attribute, dict): 171 self.as_attribute.update(Element.as_attribute) 172 173 self.as_list= {} 174 if self.xml_root.as_list: 175 self.as_list.update(self.xml_root.as_list) 176 elif isinstance(Element.as_list, dict): 177 self.as_list.update(Element.as_list) 178 179 self.as_attribute_of_element = {} 180 181 if self.xml_parent: 182 self.xml_parent.xml_children.append(self) 183 184 as_attr_elts = self.as_attribute.get(self.xml_ns, []) 185 as_list_elts = self.as_list.get(self.xml_ns, []) 186 187 if self.xml_name in as_attr_elts: 188 name = self.xml_name.replace('-', '_') 189 name = name.replace('.', '_') 190 setattr(self.xml_parent, name, self) 191 elif self.xml_name in as_list_elts: 192 name = self.xml_name.replace('-', '_') 193 name = name.replace('.', '_') 194 if not hasattr(self.xml_parent, name): 195 setattr(self.xml_parent, name, []) 196 els = getattr(self.xml_parent, name) 197 els.append(self) 198 199 if attributes and isinstance(attributes, dict): 200 for name in attributes: 201 Attribute(name, attributes[name], parent=self)
202
203 - def __repr__(self):
204 prefix = self.xml_prefix 205 xmlns = self.xml_ns 206 if (prefix not in ('', None)) and xmlns: 207 return '<%s:%s xmlns:%s="%s" element at %s />' % (prefix, self.xml_name, 208 prefix, xmlns, hex(id(self)),) 209 else: 210 return "<%s element at %s />" % (self.xml_name, hex(id(self)))
211
212 - def __unicode__(self):
213 if self.xml_text: 214 return self.xml_text 215 return unicode(None)
216
217 - def __str__(self):
218 if self.xml_text: 219 return self.xml_text.encode(self.encoding) 220 return str(None)
221
222 - def __iter__(self):
223 return iter(self.xml_children)
224
225 - def __copy__(self):
226 return Element.load(self.xml(encoding=self.encoding, omit_declaration=True))
227
228 - def clone(self):
229 return Element.load(self.xml(encoding=self.encoding, omit_declaration=True))
230
231 - def __delattr__(self, name):
232 """ 233 deletes 'name' instance of Element. It will also removes it 234 from its parent children and attributes. 235 """ 236 if not hasattr(self, name): 237 raise AttributeError, name 238 239 attr = getattr(self, name) 240 if isinstance(attr, Element): 241 if attr in self.xml_children: 242 self.xml_children.remove(attr) 243 elif isinstance(attr, Attribute): 244 if attr in self.xml_attributes: 245 self.xml_attributes.remove(attr) 246 247 del self.__dict__[name]
248
249 - def get_root(self):
250 if self._root is not None: 251 return self._root 252 253 if isinstance(self.xml_parent, Document): 254 return self 255 256 if self.xml_parent is None: 257 return self 258 return self.xml_parent.get_root()
259 xml_root = property(get_root, doc="Retrieve the top level element") 260
261 - def get_attribute(self, name):
262 for attr in self.xml_attributes: 263 if attr.xml_name == name: 264 return attr
265
266 - def get_attribute_ns(self, name, namespace):
267 for attr in self.xml_attributes: 268 if (attr.xml_name == name) and (attr.xml_ns == namespace): 269 return attr
270
271 - def has_element(self, name, ns=None):
272 """ 273 Checks if this element has 'name' attribute 274 275 Keyword arguments: 276 name -- local name of the element 277 ns -- namespace of the element 278 """ 279 obj = getattr(self, name, None) 280 if obj: 281 return obj.xml_ns == ns 282 return False
283
284 - def has_child(self, name, ns=None):
285 """ 286 Checks if this element has a child named 'name' in its children elements 287 288 Keyword arguments: 289 name -- local name of the element 290 ns -- namespace of the element 291 """ 292 return self.filtrate(fetch_child, child_name=name, child_ns=ns) != None
293
294 - def get_child(self, name, ns=None):
295 """ 296 Returns the child element named 'name', None if not found. 297 298 Keyword arguments: 299 name -- local name of the element 300 ns -- namespace of the element 301 """ 302 return self.filtrate(fetch_child, child_name=name, child_ns=ns)
303
304 - def get_children(self, name, ns=None, recursive=False):
305 """ 306 Returns the all children of this element named 'name' 307 308 Keyword arguments: 309 name -- local name of the element 310 ns -- namespace of the element 311 recursive -- if True this will iterate through the entire tree 312 """ 313 return self.filtrate(fetch_children, child_name=name, child_ns=ns, recursive=recursive)
314
315 - def forget(self):
316 """ 317 deletes this instance of Element. It will also removes it 318 from its parent children and attributes. 319 """ 320 if self.xml_parent: 321 if self in self.xml_parent.xml_children: 322 self.xml_parent.xml_children.remove(self) 323 if hasattr(self.xml_parent, self.xml_name): 324 obj = getattr(self.xml_parent, self.xml_name) 325 if isinstance(obj, list): 326 obj.remove(self) 327 elif isinstance(obj, Element): 328 del obj
329
330 - def insert_before(self, before_element, element):
331 """ 332 Insert 'element' right before 'before_element'. 333 This only inserts the new element in self.xml_children 334 335 Keyword arguments: 336 before_element -- element pivot 337 element -- new element to insert 338 """ 339 self.xml_children.insert(self.xml_children.index(before_element), element)
340
341 - def insert_after(self, after_element, element):
342 """ 343 Insert 'element' right after 'after_element'. 344 This only inserts the new element in self.xml_children 345 346 Keyword arguments: 347 after_element -- element pivot 348 element -- new element to insert 349 """ 350 self.xml_children.insert(self.xml_children.index(after_element) + 1, element)
351
352 - def xml(self, indent=True, encoding=ENCODING, prefixes=None, omit_declaration=False):
353 """ 354 Serializes as a string this element 355 356 Keyword arguments 357 indent -- pretty print the XML string (defaut: True) 358 encoding -- encoding to use during the serialization process 359 prefixes -- dictionnary of prefixes of the form {'prefix': 'ns'} 360 omit_declaration -- prevent the result to start with the XML declaration 361 """ 362 ser = self.parser() 363 return ser.serialize(self, indent=indent, encoding=encoding, 364 prefixes=prefixes, omit_declaration=omit_declaration)
365
366 - def load(self, source, prefixes=None, as_attribute=None, as_list=None, 367 as_attribute_of_element=None):
368 """ 369 Load source into an Element instance 370 371 Keyword arguments: 372 source -- an XML string, a file path or a file object 373 prefixes -- dictionnary of prefixes of the form {'prefix': 'ns'} 374 as_attribute -- dictionary of element names to set as attribute of their parent 375 as_list -- dictionary of element names to set into a list of their parent 376 as_attribute_of_element -- dictionary of attribute names to set as attribute of their 377 parent 378 379 If any of those last three parameters are provided they will take 380 precedence over those set on the Element and Attribute class. 381 382 """ 383 ser = self.parser() 384 return ser.deserialize(source, prefixes=prefixes, as_attribute=as_attribute, 385 as_list=as_list, as_attribute_of_element=as_attribute_of_element)
386 load = classmethod(load) 387