paulb@304 | 1 | #!/usr/bin/env python |
paulb@304 | 2 | |
paulb@304 | 3 | """ |
paulb@304 | 4 | XML-RPC support using libxml2dom. |
paulb@304 | 5 | |
paulb@304 | 6 | See: http://www.xmlrpc.com/spec |
paulb@304 | 7 | |
paulb@304 | 8 | Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk> |
paulb@304 | 9 | |
paulb@304 | 10 | This program is free software; you can redistribute it and/or modify it under |
paulb@304 | 11 | the terms of the GNU Lesser General Public License as published by the Free |
paulb@304 | 12 | Software Foundation; either version 3 of the License, or (at your option) any |
paulb@304 | 13 | later version. |
paulb@304 | 14 | |
paulb@304 | 15 | This program is distributed in the hope that it will be useful, but WITHOUT |
paulb@304 | 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paulb@304 | 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
paulb@304 | 18 | details. |
paulb@304 | 19 | |
paulb@304 | 20 | You should have received a copy of the GNU Lesser General Public License along |
paulb@304 | 21 | with this program. If not, see <http://www.gnu.org/licenses/>. |
paulb@304 | 22 | |
paulb@304 | 23 | -------- |
paulb@304 | 24 | |
paulb@304 | 25 | The sending and receiving of XML-RPC messages can be done using traditional HTTP |
paulb@304 | 26 | libraries. |
paulb@304 | 27 | |
paulb@304 | 28 | See tests/xmlrpc_test.py for more details. |
paulb@304 | 29 | """ |
paulb@304 | 30 | |
paulb@304 | 31 | import libxml2dom |
paulb@304 | 32 | from libxml2dom.macrolib import * |
paulb@304 | 33 | from libxml2dom.macrolib import \ |
paulb@304 | 34 | createDocument as Node_createDocument |
paulb@312 | 35 | from libxml2dom.rpc import ParameterName |
paulb@304 | 36 | |
paulb@304 | 37 | class XMLRPCImplementation(libxml2dom.Implementation): |
paulb@304 | 38 | |
paulb@304 | 39 | "Contains an XML-RPC-specific implementation." |
paulb@304 | 40 | |
paulb@304 | 41 | # Wrapping of documents. |
paulb@304 | 42 | |
paulb@304 | 43 | def adoptDocument(self, node): |
paulb@304 | 44 | return XMLRPCDocument(node, self) |
paulb@304 | 45 | |
paulb@304 | 46 | # Factory functions. |
paulb@304 | 47 | |
paulb@304 | 48 | def get_node(self, _node, context_node): |
paulb@304 | 49 | |
paulb@304 | 50 | """ |
paulb@304 | 51 | Get a libxml2dom node for the given low-level '_node' and libxml2dom |
paulb@304 | 52 | 'context_node'. |
paulb@304 | 53 | """ |
paulb@304 | 54 | |
paulb@304 | 55 | if Node_nodeType(_node) == context_node.ELEMENT_NODE: |
paulb@304 | 56 | |
paulb@304 | 57 | # Make special elements. |
paulb@304 | 58 | |
paulb@304 | 59 | if Node_localName(_node) in ("methodCall", "methodResponse"): |
paulb@304 | 60 | return XMLRPCMethodElement(_node, self, context_node.ownerDocument) |
paulb@304 | 61 | elif Node_localName(_node) == "methodName": |
paulb@304 | 62 | return XMLRPCMethodNameElement(_node, self, context_node.ownerDocument) |
paulb@304 | 63 | elif Node_localName(_node) == "fault": |
paulb@304 | 64 | return XMLRPCFaultElement(_node, self, context_node.ownerDocument) |
paulb@304 | 65 | elif Node_localName(_node) == "string": |
paulb@304 | 66 | return XMLRPCStringElement(_node, self, context_node.ownerDocument) |
paulb@304 | 67 | elif Node_localName(_node) in ("int", "i4"): |
paulb@304 | 68 | return XMLRPCIntegerElement(_node, self, context_node.ownerDocument) |
paulb@304 | 69 | elif Node_localName(_node) == "boolean": |
paulb@304 | 70 | return XMLRPCBooleanElement(_node, self, context_node.ownerDocument) |
paulb@304 | 71 | elif Node_localName(_node) == "double": |
paulb@304 | 72 | return XMLRPCDoubleElement(_node, self, context_node.ownerDocument) |
paulb@304 | 73 | elif Node_localName(_node) == "dateTime.iso8601": |
paulb@304 | 74 | return XMLRPCDateTimeElement(_node, self, context_node.ownerDocument) |
paulb@304 | 75 | elif Node_localName(_node) == "base64": |
paulb@304 | 76 | return XMLRPCBase64Element(_node, self, context_node.ownerDocument) |
paulb@304 | 77 | elif Node_localName(_node) == "struct": |
paulb@304 | 78 | return XMLRPCStructElement(_node, self, context_node.ownerDocument) |
paulb@304 | 79 | elif Node_localName(_node) == "member": |
paulb@304 | 80 | return XMLRPCMemberElement(_node, self, context_node.ownerDocument) |
paulb@307 | 81 | elif Node_localName(_node) == "value": |
paulb@307 | 82 | return XMLRPCValueElement(_node, self, context_node.ownerDocument) |
paulb@309 | 83 | elif Node_localName(_node) == "name": |
paulb@309 | 84 | return XMLRPCNameElement(_node, self, context_node.ownerDocument) |
paulb@312 | 85 | elif Node_localName(_node) == "array": |
paulb@312 | 86 | return XMLRPCArrayElement(_node, self, context_node.ownerDocument) |
paulb@312 | 87 | elif Node_localName(_node) == "data": |
paulb@312 | 88 | return XMLRPCDataElement(_node, self, context_node.ownerDocument) |
paulb@304 | 89 | |
paulb@304 | 90 | # Otherwise, make generic XML-RPC elements. |
paulb@304 | 91 | |
paulb@304 | 92 | return XMLRPCElement(_node, self, context_node.ownerDocument) |
paulb@304 | 93 | |
paulb@304 | 94 | else: |
paulb@304 | 95 | return libxml2dom.Implementation.get_node(self, _node, context_node) |
paulb@304 | 96 | |
paulb@304 | 97 | # Convenience functions. |
paulb@304 | 98 | |
paulb@304 | 99 | def createXMLRPCMessage(self, namespaceURI, localName): |
paulb@304 | 100 | |
paulb@304 | 101 | "Create a new XML-RPC message document (fragment)." |
paulb@304 | 102 | |
paulb@304 | 103 | return XMLRPCDocument(Node_createDocument(namespaceURI, localName, None), self).documentElement |
paulb@304 | 104 | |
paulb@307 | 105 | def createMethodCall(self): |
paulb@307 | 106 | return self.createXMLRPCMessage(None, "methodCall") |
paulb@307 | 107 | |
paulb@307 | 108 | def createMethodResponse(self): |
paulb@307 | 109 | return self.createXMLRPCMessage(None, "methodResponse") |
paulb@307 | 110 | |
paulb@304 | 111 | # Node classes. |
paulb@304 | 112 | |
paulb@304 | 113 | class XMLRPCNode(libxml2dom.Node): |
paulb@304 | 114 | |
paulb@304 | 115 | "Convenience modifications to nodes specific to libxml2dom.xmlrpc." |
paulb@304 | 116 | |
paulb@304 | 117 | pass |
paulb@304 | 118 | |
paulb@307 | 119 | class XMLRPCElement(XMLRPCNode): |
paulb@307 | 120 | |
paulb@307 | 121 | "An XML-RPC element." |
paulb@307 | 122 | |
paulb@307 | 123 | pass |
paulb@307 | 124 | |
paulb@304 | 125 | class XMLRPCDocument(libxml2dom._Document, XMLRPCNode): |
paulb@304 | 126 | |
paulb@304 | 127 | "An XML-RPC document fragment." |
paulb@304 | 128 | |
paulb@304 | 129 | def _method(self): |
paulb@309 | 130 | return (self.xpath("methodCall|methodResponse") or [None])[0] |
paulb@307 | 131 | |
paulb@307 | 132 | def _fault(self): |
paulb@307 | 133 | if self.method is not None: |
paulb@307 | 134 | return self.method.fault |
paulb@307 | 135 | else: |
paulb@307 | 136 | return None |
paulb@304 | 137 | |
paulb@309 | 138 | method = property(_method) |
paulb@309 | 139 | fault = property(_fault) |
paulb@309 | 140 | |
paulb@307 | 141 | # Node construction methods. |
paulb@307 | 142 | |
paulb@307 | 143 | def createMethodCall(self): |
paulb@307 | 144 | return self.ownerDocument.createElement("methodCall") |
paulb@307 | 145 | |
paulb@307 | 146 | def createMethodResponse(self): |
paulb@307 | 147 | return self.ownerDocument.createElement("methodResponse") |
paulb@307 | 148 | |
paulb@304 | 149 | class XMLRPCMethodElement(XMLRPCNode): |
paulb@304 | 150 | |
paulb@304 | 151 | "An XML-RPC method element." |
paulb@304 | 152 | |
paulb@304 | 153 | def _fault(self): |
paulb@307 | 154 | return (self.xpath("./fault") or [None])[0] |
paulb@304 | 155 | |
paulb@309 | 156 | def _methodNameElement(self): |
paulb@307 | 157 | return (self.xpath("./methodName") or [None])[0] |
paulb@307 | 158 | |
paulb@309 | 159 | def _methodName(self): |
paulb@309 | 160 | name = self.methodNameElement |
paulb@307 | 161 | if name is not None: |
paulb@307 | 162 | return name.value |
paulb@307 | 163 | else: |
paulb@307 | 164 | return None |
paulb@307 | 165 | |
paulb@309 | 166 | def _setMethodName(self, name): |
paulb@309 | 167 | if self.methodNameElement is None: |
paulb@307 | 168 | methodName = self.createMethodName() |
paulb@307 | 169 | self.appendChild(methodName) |
paulb@309 | 170 | self.methodNameElement.value = name |
paulb@304 | 171 | |
paulb@304 | 172 | def _parameters(self): |
paulb@307 | 173 | return self.xpath("./params/param") |
paulb@307 | 174 | |
paulb@312 | 175 | def _rawParameterValues(self): |
paulb@307 | 176 | values = self.xpath("./params/param/value") |
paulb@307 | 177 | if values: |
paulb@307 | 178 | items = [] |
paulb@307 | 179 | for value in values: |
paulb@309 | 180 | items.append(self._get_value(value)) |
paulb@307 | 181 | return items |
paulb@307 | 182 | else: |
paulb@307 | 183 | return [] |
paulb@304 | 184 | |
paulb@312 | 185 | def _setRawParameterValues(self, parameters): |
paulb@307 | 186 | param_list = self.parameters |
paulb@307 | 187 | params = (self.xpath("./params") or [None])[0] |
paulb@309 | 188 | |
paulb@309 | 189 | # Remove any previous parameters. |
paulb@309 | 190 | |
paulb@307 | 191 | if params: |
paulb@307 | 192 | if param_list: |
paulb@307 | 193 | for param in param_list: |
paulb@307 | 194 | params.removeChild(param) |
paulb@307 | 195 | else: |
paulb@307 | 196 | params = self.createParameters() |
paulb@307 | 197 | self.appendChild(params) |
paulb@307 | 198 | |
paulb@309 | 199 | # Add parameter values. |
paulb@309 | 200 | |
paulb@307 | 201 | for parameter in parameters: |
paulb@307 | 202 | param = self.ownerDocument.createElement("param") |
paulb@307 | 203 | params.appendChild(param) |
paulb@307 | 204 | value = self.ownerDocument.createElement("value") |
paulb@307 | 205 | param.appendChild(value) |
paulb@309 | 206 | self._add_value(value, parameter) |
paulb@307 | 207 | |
paulb@312 | 208 | def _parameterValues(self): |
paulb@312 | 209 | return libxml2dom.rpc.convert(self.rawParameterValues) |
paulb@312 | 210 | |
paulb@307 | 211 | # Internal methods. |
paulb@307 | 212 | |
paulb@309 | 213 | def _add_value(self, value, parameter): |
paulb@312 | 214 | |
paulb@312 | 215 | "Add to the 'value' element the given 'parameter'." |
paulb@312 | 216 | |
paulb@312 | 217 | (typename, parameter_name), parameter_value = parameter |
paulb@312 | 218 | |
paulb@309 | 219 | if typename == "struct": |
paulb@312 | 220 | if isinstance(parameter_value, dict): |
paulb@312 | 221 | items = parameter_value.items() |
paulb@309 | 222 | else: |
paulb@312 | 223 | items = parameter_value |
paulb@312 | 224 | |
paulb@312 | 225 | # Create a struct element and add the members. |
paulb@312 | 226 | |
paulb@309 | 227 | struct = self.ownerDocument.createElement("struct") |
paulb@312 | 228 | value.appendChild(struct) |
paulb@312 | 229 | |
paulb@312 | 230 | for item in items: |
paulb@312 | 231 | (item_typename, item_name), item_value = item |
paulb@309 | 232 | member = struct.createMember() |
paulb@309 | 233 | struct.appendChild(member) |
paulb@312 | 234 | |
paulb@312 | 235 | # Peek into the item to set up the name. |
paulb@312 | 236 | |
paulb@309 | 237 | member.memberName = item_name |
paulb@312 | 238 | |
paulb@312 | 239 | # Add the item inside a new value element. |
paulb@312 | 240 | |
paulb@309 | 241 | memberValue = member.createValue() |
paulb@309 | 242 | member.appendChild(memberValue) |
paulb@312 | 243 | self._add_value(memberValue, item) |
paulb@312 | 244 | |
paulb@312 | 245 | elif typename == "array": |
paulb@312 | 246 | |
paulb@312 | 247 | # Create an array element and add the members. |
paulb@312 | 248 | |
paulb@312 | 249 | array = self.ownerDocument.createElement("array") |
paulb@312 | 250 | value.appendChild(array) |
paulb@312 | 251 | data = array.createData() |
paulb@312 | 252 | array.appendChild(data) |
paulb@312 | 253 | |
paulb@312 | 254 | for item in parameter_value: |
paulb@312 | 255 | |
paulb@312 | 256 | # Add the item inside a new value element. |
paulb@312 | 257 | |
paulb@312 | 258 | data_value = data.createValue() |
paulb@312 | 259 | data.appendChild(data_value) |
paulb@312 | 260 | self._add_value(data_value, item) |
paulb@312 | 261 | |
paulb@309 | 262 | else: |
paulb@309 | 263 | container = self.ownerDocument.createElement(typename) |
paulb@309 | 264 | value.appendChild(container) |
paulb@312 | 265 | container.value = unicode(parameter_value) |
paulb@312 | 266 | |
paulb@312 | 267 | def _get_value(self, value, name=None): |
paulb@307 | 268 | |
paulb@312 | 269 | """ |
paulb@312 | 270 | Return the parameter name and value from within the given 'value' |
paulb@312 | 271 | element, using the optional 'name' as part of the returned name if |
paulb@312 | 272 | specified. |
paulb@312 | 273 | """ |
paulb@312 | 274 | |
paulb@307 | 275 | if value.type == "struct": |
paulb@307 | 276 | items = [] |
paulb@312 | 277 | |
paulb@312 | 278 | # Peek inside member values to get member names. |
paulb@312 | 279 | |
paulb@307 | 280 | for member in value.container.members: |
paulb@312 | 281 | items.append(self._get_value(member.value, member.memberName)) |
paulb@312 | 282 | return (ParameterName(value.type, name), items) |
paulb@312 | 283 | |
paulb@312 | 284 | elif value.type == "array": |
paulb@312 | 285 | items = [] |
paulb@312 | 286 | for data_value in value.container.data.values: |
paulb@312 | 287 | items.append(self._get_value(data_value)) |
paulb@312 | 288 | return (ParameterName(value.type, name), items) |
paulb@312 | 289 | |
paulb@307 | 290 | else: |
paulb@312 | 291 | return (ParameterName(value.type, name), value.container.value) |
paulb@307 | 292 | |
paulb@307 | 293 | # Node construction methods. |
paulb@307 | 294 | |
paulb@307 | 295 | def createMethodName(self): |
paulb@307 | 296 | return self.ownerDocument.createElement("methodName") |
paulb@307 | 297 | |
paulb@307 | 298 | def createParameters(self): |
paulb@307 | 299 | return self.ownerDocument.createElement("params") |
paulb@307 | 300 | |
paulb@304 | 301 | def createFault(self): |
paulb@304 | 302 | return self.ownerDocument.createElement("fault") |
paulb@304 | 303 | |
paulb@304 | 304 | fault = property(_fault) |
paulb@309 | 305 | methodNameElement = property(_methodNameElement) |
paulb@309 | 306 | methodName = property(_methodName, _setMethodName) |
paulb@304 | 307 | parameters = property(_parameters) |
paulb@312 | 308 | rawParameterValues = property(_rawParameterValues, _setRawParameterValues) |
paulb@312 | 309 | parameterValues = property(_parameterValues) |
paulb@312 | 310 | |
paulb@312 | 311 | class XMLRPCArrayElement(XMLRPCNode): |
paulb@312 | 312 | |
paulb@312 | 313 | "An XML-RPC array element." |
paulb@312 | 314 | |
paulb@312 | 315 | def _data(self): |
paulb@312 | 316 | return (self.xpath("./data") or [None])[0] |
paulb@312 | 317 | |
paulb@312 | 318 | # Node construction methods. |
paulb@312 | 319 | |
paulb@312 | 320 | def createData(self): |
paulb@312 | 321 | return self.ownerDocument.createElement("data") |
paulb@312 | 322 | |
paulb@312 | 323 | data = property(_data) |
paulb@309 | 324 | |
paulb@309 | 325 | class XMLRPCStructElement(XMLRPCNode): |
paulb@309 | 326 | |
paulb@309 | 327 | "An XML-RPC structure element." |
paulb@309 | 328 | |
paulb@309 | 329 | def _members(self): |
paulb@309 | 330 | return self.xpath("./member") |
paulb@309 | 331 | |
paulb@309 | 332 | # Node construction methods. |
paulb@309 | 333 | |
paulb@309 | 334 | def createMember(self): |
paulb@309 | 335 | return self.ownerDocument.createElement("member") |
paulb@309 | 336 | |
paulb@309 | 337 | members = property(_members) |
paulb@309 | 338 | |
paulb@312 | 339 | class XMLRPCDataElement(XMLRPCNode): |
paulb@312 | 340 | |
paulb@312 | 341 | "An XML-RPC array data element." |
paulb@312 | 342 | |
paulb@312 | 343 | def _values(self): |
paulb@312 | 344 | return self.xpath("./value") |
paulb@312 | 345 | |
paulb@312 | 346 | values = property(_values) |
paulb@312 | 347 | |
paulb@312 | 348 | # Node construction methods. |
paulb@312 | 349 | |
paulb@312 | 350 | def createValue(self): |
paulb@312 | 351 | return self.ownerDocument.createElement("value") |
paulb@312 | 352 | |
paulb@309 | 353 | class XMLRPCMemberElement(XMLRPCNode): |
paulb@309 | 354 | |
paulb@309 | 355 | "An XML-RPC structure member element." |
paulb@309 | 356 | |
paulb@312 | 357 | def _value(self): |
paulb@312 | 358 | return (self.xpath("./value") or [None])[0] |
paulb@312 | 359 | |
paulb@309 | 360 | def _nameElement(self): |
paulb@309 | 361 | return (self.xpath("./name") or [None])[0] |
paulb@309 | 362 | |
paulb@309 | 363 | def _memberName(self): |
paulb@309 | 364 | if self.nameElement is not None: |
paulb@309 | 365 | return self.nameElement.value |
paulb@309 | 366 | else: |
paulb@309 | 367 | return None |
paulb@309 | 368 | |
paulb@309 | 369 | def _setMemberName(self, name): |
paulb@309 | 370 | if self.nameElement is None: |
paulb@309 | 371 | nameElement = self.createName() |
paulb@309 | 372 | self.appendChild(nameElement) |
paulb@309 | 373 | self.nameElement.value = name |
paulb@309 | 374 | |
paulb@309 | 375 | # Node construction methods. |
paulb@309 | 376 | |
paulb@309 | 377 | def createName(self): |
paulb@309 | 378 | return self.ownerDocument.createElement("name") |
paulb@309 | 379 | |
paulb@309 | 380 | def createValue(self): |
paulb@309 | 381 | return self.ownerDocument.createElement("value") |
paulb@309 | 382 | |
paulb@312 | 383 | value = property(_value) |
paulb@309 | 384 | nameElement = property(_nameElement) |
paulb@309 | 385 | memberName = property(_memberName, _setMemberName) |
paulb@304 | 386 | |
paulb@304 | 387 | class XMLRPCStringElement(XMLRPCNode): |
paulb@304 | 388 | |
paulb@304 | 389 | "An XML-RPC string element." |
paulb@304 | 390 | |
paulb@304 | 391 | def _value(self): |
paulb@304 | 392 | return self.textContent.strip() |
paulb@304 | 393 | |
paulb@304 | 394 | def _setValue(self, value): |
paulb@304 | 395 | for node in self.childNodes: |
paulb@304 | 396 | self.removeChild(node) |
paulb@304 | 397 | text = self.ownerDocument.createTextNode(value) |
paulb@304 | 398 | self.appendChild(text) |
paulb@304 | 399 | |
paulb@304 | 400 | value = property(_value, _setValue) |
paulb@304 | 401 | |
paulb@309 | 402 | class XMLRPCNameElement(XMLRPCStringElement): |
paulb@309 | 403 | |
paulb@309 | 404 | "An XML-RPC name element." |
paulb@309 | 405 | |
paulb@309 | 406 | pass |
paulb@309 | 407 | |
paulb@307 | 408 | class XMLRPCValueElement(XMLRPCStringElement): |
paulb@307 | 409 | |
paulb@307 | 410 | "An XML-RPC value element." |
paulb@307 | 411 | |
paulb@307 | 412 | def _type(self): |
paulb@307 | 413 | elements = self.xpath("*") |
paulb@307 | 414 | if elements: |
paulb@307 | 415 | return elements[0].localName |
paulb@307 | 416 | else: |
paulb@307 | 417 | return "string" |
paulb@307 | 418 | |
paulb@307 | 419 | def _container(self): |
paulb@307 | 420 | return (self.xpath("*") or [self])[0] |
paulb@307 | 421 | |
paulb@307 | 422 | type = property(_type) |
paulb@307 | 423 | container = property(_container) |
paulb@307 | 424 | |
paulb@304 | 425 | class XMLRPCMethodNameElement(XMLRPCStringElement): |
paulb@304 | 426 | |
paulb@304 | 427 | "An XML-RPC method element." |
paulb@304 | 428 | |
paulb@304 | 429 | pass |
paulb@304 | 430 | |
paulb@304 | 431 | class XMLRPCIntegerElement(XMLRPCStringElement): |
paulb@304 | 432 | |
paulb@304 | 433 | "An XML-RPC integer element." |
paulb@304 | 434 | |
paulb@304 | 435 | pass |
paulb@304 | 436 | |
paulb@304 | 437 | class XMLRPCBooleanElement(XMLRPCStringElement): |
paulb@304 | 438 | |
paulb@304 | 439 | "An XML-RPC boolean element." |
paulb@304 | 440 | |
paulb@304 | 441 | pass |
paulb@304 | 442 | |
paulb@304 | 443 | class XMLRPCDoubleElement(XMLRPCStringElement): |
paulb@304 | 444 | |
paulb@304 | 445 | "An XML-RPC double floating point number element." |
paulb@304 | 446 | |
paulb@304 | 447 | pass |
paulb@304 | 448 | |
paulb@304 | 449 | class XMLRPCDateTimeElement(XMLRPCStringElement): |
paulb@304 | 450 | |
paulb@304 | 451 | "An XML-RPC date/time element." |
paulb@304 | 452 | |
paulb@304 | 453 | pass |
paulb@304 | 454 | |
paulb@304 | 455 | class XMLRPCBase64Element(XMLRPCStringElement): |
paulb@304 | 456 | |
paulb@304 | 457 | "An XML-RPC integer element." |
paulb@304 | 458 | |
paulb@304 | 459 | pass |
paulb@304 | 460 | |
paulb@304 | 461 | class XMLRPCFaultElement(XMLRPCNode): |
paulb@304 | 462 | |
paulb@304 | 463 | "An XML-RPC fault element." |
paulb@304 | 464 | |
paulb@304 | 465 | def _code(self): |
paulb@307 | 466 | code = self.xpath("./value/struct/member[./name/text() = 'faultCode']/value/int") |
paulb@307 | 467 | if code: |
paulb@307 | 468 | return code[0].value |
paulb@307 | 469 | else: |
paulb@307 | 470 | return None |
paulb@304 | 471 | |
paulb@304 | 472 | def _reason(self): |
paulb@307 | 473 | reason = self.xpath("./value/struct/member[./name/text() = 'faultString']/value/string") |
paulb@307 | 474 | if reason: |
paulb@307 | 475 | return reason[0].value |
paulb@307 | 476 | else: |
paulb@307 | 477 | return None |
paulb@304 | 478 | |
paulb@304 | 479 | code = property(_code) |
paulb@304 | 480 | reason = property(_reason) |
paulb@304 | 481 | |
paulb@304 | 482 | # Utility functions. |
paulb@304 | 483 | |
paulb@304 | 484 | createDocument = libxml2dom.createDocument |
paulb@304 | 485 | createDocumentType = libxml2dom.createDocumentType |
paulb@304 | 486 | |
paulb@304 | 487 | def createXMLRPCMessage(namespaceURI, localName): |
paulb@307 | 488 | return default_impl.createXMLRPCMessage(None, localName) |
paulb@307 | 489 | |
paulb@307 | 490 | def createMethodCall(): |
paulb@307 | 491 | return default_impl.createMethodCall() |
paulb@307 | 492 | |
paulb@307 | 493 | def createMethodResponse(): |
paulb@307 | 494 | return default_impl.createMethodResponse() |
paulb@304 | 495 | |
paulb@304 | 496 | def parse(stream_or_string, html=0, htmlencoding=None, unfinished=0, impl=None): |
paulb@304 | 497 | return libxml2dom.parse(stream_or_string, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl)) |
paulb@304 | 498 | |
paulb@304 | 499 | def parseFile(filename, html=0, htmlencoding=None, unfinished=0, impl=None): |
paulb@304 | 500 | return libxml2dom.parseFile(filename, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl)) |
paulb@304 | 501 | |
paulb@304 | 502 | def parseString(s, html=0, htmlencoding=None, unfinished=0, impl=None): |
paulb@304 | 503 | return libxml2dom.parseString(s, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl)) |
paulb@304 | 504 | |
paulb@304 | 505 | def parseURI(uri, html=0, htmlencoding=None, unfinished=0, impl=None): |
paulb@304 | 506 | return libxml2dom.parseURI(uri, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl)) |
paulb@304 | 507 | |
paulb@304 | 508 | # Single instance of the implementation. |
paulb@304 | 509 | |
paulb@304 | 510 | default_impl = XMLRPCImplementation() |
paulb@304 | 511 | |
paulb@304 | 512 | # vim: tabstop=4 expandtab shiftwidth=4 |