Package ndg :: Package soap :: Module etree
[hide private]

Source Code for Module ndg.soap.etree

  1  """SOAP client package - XML representation using ElementTree 
  2   
  3  NERC DataGrid Project 
  4  """ 
  5  __author__ = "P J Kershaw" 
  6  __date__ = "27/07/09" 
  7  __copyright__ = "(C) 2010 Science and Technology Facilities Council" 
  8  __license__ = "http://www.apache.org/licenses/LICENSE-2.0" 
  9  __contact__ = "Philip.Kershaw@stfc.ac.uk" 
 10  __revision__ = '$Id: etree.py 7131 2010-06-30 13:37:48Z pjkersha $' 
 11  import logging 
 12  log = logging.getLogger(__name__) 
 13   
 14  from ndg.saml import Config, importElementTreeAndCElementTree 
 15  (ElementTree, cElementTree) = importElementTreeAndCElementTree() 
 16   
 17  # ElementTree helper functions 
 18  import ndg.soap.utils.etree as etree 
 19  from ndg.soap.utils.etree import QName 
 20   
 21  from ndg.soap import (SOAPObject, SOAPEnvelopeBase, SOAPHeaderBase,  
 22                        SOAPBodyBase, SOAPFaultBase) 
 23  from ndg.soap import SOAPFaultException as SOAPFaultExceptionBase 
24 25 26 -class ETreeSOAPExtensions(object):
27 """Utility to enable addition of core ElementTree specific attributes and 28 methods for ElementTree SOAP implementation 29 """
30 - def __init__(self):
31 self.__qname = None 32 self.__elem = None
33
34 - def _getQname(self):
35 return self.__qname
36
37 - def _setQname(self, value):
38 if not isinstance(value, QName): 39 raise TypeError('Expecting %r for "qname" attribute; got %r' % 40 (QName, type(value))) 41 self.__qname = value
42
43 - def _getElem(self):
44 return self.__elem
45
46 - def _setElem(self, value):
47 if not ElementTree.iselement(value): 48 raise TypeError('Expecting %r for "elem" attribute; got %r' % 49 (ElementTree.Element, type(value))) 50 self.__elem = value
51 52 qname = property(_getQname, _setQname, None, "Qualified name object") 53 elem = property(_getElem, _setElem, None, "Root element") 54 55 @staticmethod
56 - def _serialize(elem):
57 """Serialise element tree into string""" 58 if Config.use_lxml: 59 return ElementTree.tostring(elem) 60 else: 61 return cElementTree.tostring(elem)
62 63 @classmethod
64 - def _prettyPrint(cls, elem):
65 """Basic pretty printing separating each element on to a new line""" 66 xml = cls._serialize(elem) 67 xml = ">\n".join(xml.split(">")) 68 xml = "\n<".join(xml.split("<")) 69 xml = '\n'.join(xml.split('\n\n')) 70 return xml
71 72 @staticmethod
73 - def _parse(source):
74 """Read in the XML from source 75 @type source: basestring/file 76 @param source: file path to XML file or file object 77 """ 78 tree = ElementTree.parse(source) 79 elem = tree.getroot() 80 81 return elem
82
83 84 -class SOAPHeader(SOAPHeaderBase, ETreeSOAPExtensions):
85 """ElementTree implementation of SOAP Header object""" 86 87 DEFAULT_ELEMENT_NAME = QName(SOAPHeaderBase.DEFAULT_ELEMENT_NS, 88 tag=SOAPHeaderBase.DEFAULT_ELEMENT_LOCAL_NAME, 89 prefix=SOAPHeaderBase.DEFAULT_ELEMENT_NS_PREFIX) 90
91 - def __init__(self):
98
99 - def create(self):
100 """Create header ElementTree element""" 101 102 self.elem = etree.makeEtreeElement(str(self.qname), 103 SOAPHeaderBase.DEFAULT_ELEMENT_NS_PREFIX, 104 SOAPHeaderBase.DEFAULT_ELEMENT_NS)
105
106 - def serialize(self):
107 """Serialise element tree into string""" 108 return ETreeSOAPExtensions._serialize(self.elem)
109
110 - def prettyPrint(self):
111 """Basic pretty printing separating each element on to a new line""" 112 return ETreeSOAPExtensions._prettyPrint(self.elem)
113
114 115 -class SOAPBody(SOAPBodyBase, ETreeSOAPExtensions):
116 """ElementTree based implementation for SOAP Body object""" 117 118 DEFAULT_ELEMENT_NAME = QName(SOAPBodyBase.DEFAULT_ELEMENT_NS, 119 tag=SOAPBodyBase.DEFAULT_ELEMENT_LOCAL_NAME, 120 prefix=SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX) 121
122 - def __init__(self):
130 131 # Test for SOAPFault present 132 @property
133 - def hasSOAPFault(self):
134 """Boolean True if this SOAP BOdy contains a SOAPFault instance""" 135 return self.fault is not None
136
137 - def _getFault(self):
138 return self.__fault
139
140 - def _setFault(self, value):
141 if not isinstance(value, SOAPFault): 142 raise TypeError('Expecting %r type for "fault" attribute; got %r' % 143 (SOAPFault, type(value))) 144 self.__fault = value
145 146 fault = property(_getFault, _setFault, doc="SOAP Fault") 147
148 - def create(self):
149 """Create header ElementTree element""" 150 self.elem = etree.makeEtreeElement(str(self.qname), 151 SOAPBodyBase.DEFAULT_ELEMENT_NS_PREFIX, 152 SOAPBodyBase.DEFAULT_ELEMENT_NS) 153 if self.hasSOAPFault: 154 self.fault.create() 155 self.elem.append(self.fault.elem)
156
157 - def serialize(self):
158 """Serialise element tree into string""" 159 return ETreeSOAPExtensions._serialize(self.elem)
160
161 - def parse(self, source):
162 """This method ONLY parses a SOAPFault IF one is found""" 163 if ElementTree.iselement(source): 164 self.elem = source 165 else: 166 self.elem = self._parse(source) 167 168 for elem in self.elem: 169 localName = QName.getLocalPart(elem.tag) 170 if localName == SOAPFault.DEFAULT_ELEMENT_LOCAL_NAME: 171 if self.fault is None: 172 self.fault = SOAPFault() 173 174 self.fault.parse(elem) 175 176 # Only one SOAPFault element is expected 177 break
178
179 - def prettyPrint(self):
180 """Basic pretty printing separating each element on to a new line""" 181 return ETreeSOAPExtensions._prettyPrint(self.elem)
182
183 184 -class SOAPFault(SOAPFaultBase, ETreeSOAPExtensions):
185 """Extend SOAP Fault for ElementTree parsing and serialisation""" 186 187 DEFAULT_ELEMENT_NAME = QName(SOAPFaultBase.DEFAULT_ELEMENT_NS, 188 tag=SOAPFaultBase.DEFAULT_ELEMENT_LOCAL_NAME, 189 prefix=SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX) 190 191 FAULT_CODE_ELEMENT_NAME = QName(SOAPFaultBase.DEFAULT_ELEMENT_NS, 192 tag=SOAPFaultBase.FAULT_CODE_ELEMENT_LOCAL_NAME, 193 prefix=SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX) 194 195 FAULT_STRING_ELEMENT_NAME = QName(SOAPFaultBase.DEFAULT_ELEMENT_NS, 196 tag=SOAPFaultBase.FAULT_STRING_ELEMENT_LOCAL_NAME, 197 prefix=SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX) 198 199 FAULT_ACTOR_ELEMENT_NAME = QName(SOAPFaultBase.DEFAULT_ELEMENT_NS, 200 tag=SOAPFaultBase.FAULT_ACTOR_ELEMENT_LOCAL_NAME, 201 prefix=SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX) 202 203 DETAIL_ELEMENT_NAME = QName(SOAPFaultBase.DEFAULT_ELEMENT_NS, 204 tag=SOAPFaultBase.DETAIL_ELEMENT_LOCAL_NAME, 205 prefix=SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX) 206
207 - def __init__(self, *arg, **kw):
214
215 - def _setFaultCode(self, value):
216 """Override to enable ns prefix to be inferred if not added in already 217 """ 218 if value.startswith(self.__class__.FAULT_CODE_ELEMENT_NAME.prefix): 219 _value = value 220 else: 221 _value = "%s:%s" % (SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX, value) 222 223 SOAPFaultBase._setFaultCode(self, _value)
224 225 faultCode = property(SOAPFaultBase._getFaultCode, _setFaultCode, 226 doc="Fault code") 227
228 - def create(self):
229 """Create Fault ElementTree element""" 230 self.elem = etree.makeEtreeElement(str(self.qname), 231 SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX, 232 SOAPFaultBase.DEFAULT_ELEMENT_NS) 233 234 faultStringElem = etree.makeEtreeElement( 235 str(self.__class__.FAULT_STRING_ELEMENT_NAME), 236 SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX, 237 SOAPFaultBase.DEFAULT_ELEMENT_NS) 238 faultStringElem.text = self.faultString 239 self.elem.append(faultStringElem) 240 241 faultCodeElem = etree.makeEtreeElement( 242 str(self.__class__.FAULT_CODE_ELEMENT_NAME), 243 SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX, 244 SOAPFaultBase.DEFAULT_ELEMENT_NS) 245 faultCodeElem.text = self.faultCode 246 self.elem.append(faultCodeElem) 247 248 if self.faultActor is not None: 249 faultActorElem = etree.makeEtreeElement( 250 str(self.__class__.FAULT_ACTOR_ELEMENT_NAME), 251 SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX, 252 SOAPFaultBase.DEFAULT_ELEMENT_NS) 253 faultActorElem.text = self.faultActor 254 self.elem.append(faultActorElem) 255 256 if self.detail is not None: 257 detailElem = etree.makeEtreeElement( 258 str(self.__class__.DETAIL_ELEMENT_NAME), 259 SOAPFaultBase.DEFAULT_ELEMENT_NS_PREFIX, 260 SOAPFaultBase.DEFAULT_ELEMENT_NS) 261 262 if ElementTree.iselement(self.detail): 263 detailElem.append(self.detail) 264 265 elif isinstance(self.detail, basestring): 266 detailElem.text = self.detail 267 else: 268 raise TypeError('Expecting ElementTree.Element or string ' 269 'type for SOAPFault detail; got %r' % 270 type(self.detail)) 271 272 self.elem.append(detailElem)
273
274 - def parse(self, source):
275 """Parse SOAPFault element""" 276 if ElementTree.iselement(source): 277 self.elem = source 278 else: 279 self.elem = self._parse(source) 280 281 for elem in self.elem: 282 localName = QName.getLocalPart(elem.tag) 283 if localName == SOAPFault.FAULT_CODE_ELEMENT_LOCAL_NAME: 284 self.faultCode = elem.text.strip() 285 286 elif localName == SOAPFault.FAULT_STRING_ELEMENT_LOCAL_NAME: 287 self.faultString = elem.text.strip() 288 289 elif localName == SOAPFault.FAULT_ACTOR_ELEMENT_LOCAL_NAME: 290 self.faultActor = elem.text.strip() 291 292 elif localName == SOAPFault.DETAIL_ELEMENT_LOCAL_NAME: 293 # Make no assumptions about the content, simply assing the 294 # element to the detail attribute 295 self.detail = elem 296 297 else: 298 faultCode = str(QName(SOAPFault.DEFAULT_ELEMENT_NS, 299 tag=SOAPFault.CLIENT_FAULT_CODE, 300 prefix=SOAPFault.DEFAULT_ELEMENT_NS_PREFIX)) 301 302 raise SOAPFaultException('Invalid child element in SOAP ' 303 'Fault "%s" for stream %r' % 304 (localName, source), 305 faultCode)
306
307 - def serialize(self):
308 """Serialise element tree into string""" 309 return ETreeSOAPExtensions._serialize(self.elem)
310
311 - def prettyPrint(self):
312 """Basic pretty printing separating each element on to a new line""" 313 return ETreeSOAPExtensions._prettyPrint(self.elem)
314
315 316 -class SOAPFaultException(SOAPFaultExceptionBase):
317 """Extend SOAP Fault Exception base class to use ElementTree based 318 SOAP Fault implementation for parsing and serialisation""" 319 SOAP_FAULT_CLASS = SOAPFault
320
321 322 -class SOAPEnvelope(SOAPEnvelopeBase, ETreeSOAPExtensions):
323 """ElementTree based SOAP implementation""" 324 DEFAULT_ELEMENT_NAME = QName(SOAPEnvelopeBase.DEFAULT_ELEMENT_NS, 325 tag=SOAPEnvelopeBase.DEFAULT_ELEMENT_LOCAL_NAME, 326 prefix=SOAPEnvelopeBase.DEFAULT_ELEMENT_NS_PREFIX) 327
328 - def __init__(self):
337
338 - def _getHeader(self):
339 return self.__header
340
341 - def _setHeader(self, value):
342 if not isinstance(value, SOAPHeader): 343 raise TypeError('Expecting %r for "header" attribute; got %r' % 344 (SOAPHeader, type(value))) 345 self.__header = value
346
347 - def _getBody(self):
348 return self.__body
349
350 - def _setBody(self, value):
351 if not isinstance(value, SOAPBody): 352 raise TypeError('Expecting %r for "header" attribute; got %r' % 353 (SOAPBody, type(value))) 354 self.__body = value
355 356 header = property(_getHeader, _setHeader, None, "SOAP header object") 357 body = property(_getBody, _setBody, None, "SOAP body object") 358
359 - def create(self):
360 """Create SOAP Envelope with header and body""" 361 362 self.elem = etree.makeEtreeElement(str(self.qname), 363 SOAPEnvelopeBase.DEFAULT_ELEMENT_NS_PREFIX, 364 SOAPEnvelopeBase.DEFAULT_ELEMENT_NS) 365 366 self.header.create() 367 self.elem.append(self.header.elem) 368 369 self.body.create() 370 self.elem.append(self.body.elem)
371
372 - def serialize(self):
373 """Serialise element tree into string""" 374 return ETreeSOAPExtensions._serialize(self.elem)
375
376 - def prettyPrint(self):
377 """Basic pretty printing separating each element onto a new line""" 378 return ETreeSOAPExtensions._prettyPrint(self.elem)
379
380 - def parse(self, source):
381 """Parse SOAP Envelope""" 382 self.elem = self._parse(source) 383 384 for elem in self.elem: 385 localName = QName.getLocalPart(elem.tag) 386 if localName == SOAPHeader.DEFAULT_ELEMENT_LOCAL_NAME: 387 self.header.elem = elem 388 389 elif localName == SOAPBody.DEFAULT_ELEMENT_LOCAL_NAME: 390 self.body.parse(elem) 391 else: 392 faultCode = str(QName(SOAPEnvelopeBase.DEFAULT_ELEMENT_NS, 393 tag=SOAPFault.CLIENT_FAULT_CODE, 394 prefix=SOAPFault.DEFAULT_ELEMENT_NS_PREFIX)) 395 396 raise SOAPFaultException('Invalid child element in SOAP ' 397 'Envelope "%s" for stream %r' % 398 (localName, source), 399 faultCode)
400