1.1 --- a/libxml2dom/soap.py Sun Sep 30 00:57:06 2007 +0000
1.2 +++ b/libxml2dom/soap.py Sun Sep 30 23:23:40 2007 +0000
1.3 @@ -134,6 +134,29 @@
1.4
1.5 envelope = property(_envelope)
1.6
1.7 + # Convenience methods and properties.
1.8 +
1.9 + def _methodName(self):
1.10 + return self.envelope.body.methodName
1.11 +
1.12 + def _parameterItems(self):
1.13 + return self.envelope.body.parameterItems
1.14 +
1.15 + def _parameterValues(self):
1.16 + return self.envelope.body.parameterValues
1.17 +
1.18 + def _parameterMap(self):
1.19 + return self.envelope.body.parameterMap
1.20 +
1.21 + def _fault(self):
1.22 + return self.envelope.body.fault
1.23 +
1.24 + methodName = property(_methodName)
1.25 + parameterItems = property(_parameterItems)
1.26 + parameterValues = property(_parameterValues)
1.27 + parameterMap = property(_parameterMap)
1.28 + fault = property(_fault)
1.29 +
1.30 class SOAPElement(SOAPNode):
1.31
1.32 "A SOAP element."
1.33 @@ -169,30 +192,84 @@
1.34 "A SOAP body element."
1.35
1.36 def _fault(self):
1.37 - return self.xpath("./env:Fault")[0]
1.38 + return (self.xpath("./env:Fault") or [None])[0]
1.39
1.40 def _method(self):
1.41 - return self.xpath("./*[@env:encodingStyle = '%s']" % SOAP_ENCODING_NAMESPACE)[0]
1.42 + return (self.xpath("./*[@env:encodingStyle = '%s']" % SOAP_ENCODING_NAMESPACE) or [None])[0]
1.43
1.44 def _methodName(self):
1.45 - return self.method.localName
1.46 + if self.method is not None:
1.47 + return self.method.localName
1.48 + else:
1.49 + return None
1.50
1.51 def _resultParameter(self):
1.52 - return self.method.xpath(".//rpc:result")[0]
1.53 + return (self.method.xpath(".//rpc:result") or [None])[0]
1.54
1.55 def _resultParameterValue(self):
1.56 - name = self.resultParameter.textContent.strip()
1.57 - return self.method.xpath(".//%s" % name, namespaces={self.method.prefix : self.method.namespaceURI})[0].textContent.strip()
1.58 + if self.resultParameter:
1.59 + name = self.resultParameter.textContent.strip()
1.60 + result = self.method.xpath(".//%s" % name, namespaces={self.method.prefix : self.method.namespaceURI})
1.61 + if result:
1.62 + return result[0].textContent.strip()
1.63 + else:
1.64 + return None
1.65 + else:
1.66 + return None
1.67
1.68 def _parameters(self):
1.69 - return self.method.xpath(".//*[not(./*)]")
1.70 + if self.method is not None:
1.71 + return self.method.xpath("*")
1.72 + else:
1.73 + return []
1.74 +
1.75 + def _parameterItems(self):
1.76 + values = []
1.77 + for parameter in self.parameters:
1.78 + values.append(self._item_contents(parameter))
1.79 + return values
1.80
1.81 def _parameterValues(self):
1.82 - values = {}
1.83 - for parameter in self.parameters:
1.84 - values[(parameter.namespaceURI, parameter.localName)] = parameter.textContent.strip()
1.85 + return self._value_contents(self.parameterItems)
1.86 +
1.87 + def _parameterMap(self):
1.88 + return self._map_contents(self.parameterItems)
1.89 +
1.90 + # Internal methods.
1.91 +
1.92 + def _item_contents(self, parameter):
1.93 + elements = parameter.xpath("*")
1.94 + if elements:
1.95 + items = []
1.96 + for element in elements:
1.97 + items.append(self._item_contents(element))
1.98 + return (parameter.namespaceURI, parameter.localName), items
1.99 + else:
1.100 + return (parameter.namespaceURI, parameter.localName), parameter.textContent.strip()
1.101 +
1.102 + def _value_contents(self, items):
1.103 + values = []
1.104 + for (typename, name), value in items:
1.105 + if isinstance(value, list):
1.106 + values.append(self._value_contents(value))
1.107 + elif name is None:
1.108 + values.append(value)
1.109 + else:
1.110 + values.append((name, value))
1.111 return values
1.112
1.113 + def _map_contents(self, items):
1.114 + d = {}
1.115 + for n, ((typename, name), value) in enumerate(items):
1.116 + key_name = name or str(n)
1.117 + if isinstance(value, list):
1.118 + d[(typename, key_name)] = self._map_contents(value)
1.119 + else:
1.120 + d[(typename, key_name)] = value
1.121 + return d
1.122 +
1.123 + # Node construction methods.
1.124 +
1.125 def createFault(self):
1.126 return self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Fault")
1.127
1.128 @@ -202,25 +279,39 @@
1.129 resultParameter = property(_resultParameter)
1.130 resultParameterValue = property(_resultParameterValue)
1.131 parameters = property(_parameters)
1.132 + parameterItems = property(_parameterItems)
1.133 parameterValues = property(_parameterValues)
1.134 + parameterMap = property(_parameterMap)
1.135
1.136 class SOAPFaultElement(SOAPNode):
1.137
1.138 "A SOAP fault element."
1.139
1.140 def _code(self):
1.141 - return self.xpath("./env:Code")[0]
1.142 + code = self.xpath("./env:Code")
1.143 + if code:
1.144 + return code[0].value
1.145 + else:
1.146 + return None
1.147 +
1.148 + def _subcode(self):
1.149 + subcode = self.xpath("./env:Code/env:Subcode")
1.150 + if subcode:
1.151 + return subcode[0].value
1.152 + else:
1.153 + return None
1.154
1.155 def _reason(self):
1.156 - return self.xpath("./env:Reason")[0]
1.157 + return (self.xpath("./env:Reason") or [None])[0]
1.158
1.159 def _detail(self):
1.160 - return self.xpath("./env:Detail")[0]
1.161 + return (self.xpath("./env:Detail") or [None])[0]
1.162
1.163 def createCode(self):
1.164 return self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Code")
1.165
1.166 code = property(_code)
1.167 + subcode = property(_subcode)
1.168 reason = property(_reason)
1.169 detail = property(_detail)
1.170
1.171 @@ -229,7 +320,11 @@
1.172 "A SOAP subcode element."
1.173
1.174 def _value(self):
1.175 - return self.xpath("./env:Value")[0].textContent.strip()
1.176 + value = self.xpath("./env:Value")
1.177 + if value:
1.178 + return value[0].textContent.strip()
1.179 + else:
1.180 + return None
1.181
1.182 def _setValue(self, value):
1.183 nodes = self.xpath("./env:Value")
1.184 @@ -253,7 +348,7 @@
1.185 "A SOAP code element."
1.186
1.187 def _subcode(self):
1.188 - return self.xpath("./env:Subcode")[0]
1.189 + return (self.xpath("./env:Subcode") or [None])[0]
1.190
1.191 def createSubcode(self):
1.192 return self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Subcode")
2.1 --- a/libxml2dom/xmlrpc.py Sun Sep 30 00:57:06 2007 +0000
2.2 +++ b/libxml2dom/xmlrpc.py Sun Sep 30 23:23:40 2007 +0000
2.3 @@ -32,6 +32,7 @@
2.4 from libxml2dom.macrolib import *
2.5 from libxml2dom.macrolib import \
2.6 createDocument as Node_createDocument
2.7 +import datetime
2.8
2.9 class XMLRPCImplementation(libxml2dom.Implementation):
2.10
2.11 @@ -77,6 +78,8 @@
2.12 return XMLRPCStructElement(_node, self, context_node.ownerDocument)
2.13 elif Node_localName(_node) == "member":
2.14 return XMLRPCMemberElement(_node, self, context_node.ownerDocument)
2.15 + elif Node_localName(_node) == "value":
2.16 + return XMLRPCValueElement(_node, self, context_node.ownerDocument)
2.17
2.18 # Otherwise, make generic XML-RPC elements.
2.19
2.20 @@ -93,6 +96,25 @@
2.21
2.22 return XMLRPCDocument(Node_createDocument(namespaceURI, localName, None), self).documentElement
2.23
2.24 + def createMethodCall(self):
2.25 + return self.createXMLRPCMessage(None, "methodCall")
2.26 +
2.27 + def createMethodResponse(self):
2.28 + return self.createXMLRPCMessage(None, "methodResponse")
2.29 +
2.30 +# Internal utility functions.
2.31 +
2.32 +def boolean(s):
2.33 + if s.lower() == "true":
2.34 + return True
2.35 + elif s.lower() == "false":
2.36 + return False
2.37 + else:
2.38 + raise ValueError, "String value %s not convertable to boolean." % repr(s)
2.39 +
2.40 +def iso8601(s):
2.41 + return s
2.42 +
2.43 # Node classes.
2.44
2.45 class XMLRPCNode(libxml2dom.Node):
2.46 @@ -101,47 +123,213 @@
2.47
2.48 pass
2.49
2.50 +class XMLRPCElement(XMLRPCNode):
2.51 +
2.52 + "An XML-RPC element."
2.53 +
2.54 + pass
2.55 +
2.56 class XMLRPCDocument(libxml2dom._Document, XMLRPCNode):
2.57
2.58 "An XML-RPC document fragment."
2.59
2.60 def _method(self):
2.61 - return self.xpath("./methodCall|./methodResponse")[0]
2.62 + return (self.xpath("./methodCall|./methodResponse") or [None])[0]
2.63
2.64 method = property(_method)
2.65
2.66 -class XMLRPCElement(XMLRPCNode):
2.67 + # Convenience methods and properties.
2.68 +
2.69 + def _methodName(self):
2.70 + if self.method is not None:
2.71 + return self.method.name
2.72 + else:
2.73 + return None
2.74 +
2.75 + def _parameterItems(self):
2.76 + if self.method is not None:
2.77 + return self.method.parameterItems
2.78 + else:
2.79 + return None
2.80 +
2.81 + def _parameterValues(self):
2.82 + if self.method is not None:
2.83 + return self.method.parameterValues
2.84 + else:
2.85 + return None
2.86
2.87 - "An XML-RPC element."
2.88 + def _parameterMap(self):
2.89 + if self.method is not None:
2.90 + return self.method.parameterMap
2.91 + else:
2.92 + return None
2.93 +
2.94 + def _fault(self):
2.95 + if self.method is not None:
2.96 + return self.method.fault
2.97 + else:
2.98 + return None
2.99
2.100 - pass
2.101 + # Node construction methods.
2.102 +
2.103 + def createMethodCall(self):
2.104 + return self.ownerDocument.createElement("methodCall")
2.105 +
2.106 + def createMethodResponse(self):
2.107 + return self.ownerDocument.createElement("methodResponse")
2.108 +
2.109 + methodName = property(_methodName)
2.110 + parameterItems = property(_parameterItems)
2.111 + parameterValues = property(_parameterValues)
2.112 + parameterMap = property(_parameterMap)
2.113 + fault = property(_fault)
2.114
2.115 class XMLRPCMethodElement(XMLRPCNode):
2.116
2.117 "An XML-RPC method element."
2.118
2.119 def _fault(self):
2.120 - return self.xpath("./fault")[0]
2.121 + return (self.xpath("./fault") or [None])[0]
2.122
2.123 def _methodName(self):
2.124 - return self.xpath("./methodName")[0]
2.125 + return (self.xpath("./methodName") or [None])[0]
2.126 +
2.127 + def _name(self):
2.128 + name = self.methodName
2.129 + if name is not None:
2.130 + return name.value
2.131 + else:
2.132 + return None
2.133 +
2.134 + def _setName(self, name):
2.135 + if self.methodName is None:
2.136 + methodName = self.createMethodName()
2.137 + self.appendChild(methodName)
2.138 + self.methodName.value = name
2.139
2.140 def _parameters(self):
2.141 - return self.xpath("./params/param/value//*[not(./*)]")
2.142 + return self.xpath("./params/param")
2.143 +
2.144 + def _parameterItems(self):
2.145 + values = self.xpath("./params/param/value")
2.146 + if values:
2.147 + items = []
2.148 + for value in values:
2.149 + items.append(self._item_contents(value))
2.150 + return items
2.151 + else:
2.152 + return []
2.153
2.154 def _parameterValues(self):
2.155 - values = {}
2.156 - for parameter in self.parameters:
2.157 - values[(parameter.namespaceURI, parameter.localName)] = parameter.textContent.strip()
2.158 + return self._value_contents(self.parameterItems)
2.159 +
2.160 + def _setParameterValues(self, parameters):
2.161 + param_list = self.parameters
2.162 + params = (self.xpath("./params") or [None])[0]
2.163 + if params:
2.164 + if param_list:
2.165 + for param in param_list:
2.166 + params.removeChild(param)
2.167 + else:
2.168 + params = self.createParameters()
2.169 + self.appendChild(params)
2.170 +
2.171 + for parameter in parameters:
2.172 + param = self.ownerDocument.createElement("param")
2.173 + params.appendChild(param)
2.174 + value = self.ownerDocument.createElement("value")
2.175 + param.appendChild(value)
2.176 +
2.177 + # NOTE: Only handles simple types.
2.178 +
2.179 + container = self._make_container(parameter)
2.180 + value.appendChild(container)
2.181 + text = self.ownerDocument.createTextNode(unicode(parameter))
2.182 + container.appendChild(text)
2.183 +
2.184 + def _parameterMap(self):
2.185 + return self._map_contents(self.parameterItems)
2.186 +
2.187 + # Internal data.
2.188 +
2.189 + converters = {
2.190 + "string" : unicode,
2.191 + "int" : int,
2.192 + "i4" : int,
2.193 + "double" : float,
2.194 + "boolean" : boolean, # see the module globals
2.195 + "dateTime.iso8601" : iso8601, # see the module globals
2.196 + "base64" : str
2.197 + }
2.198 +
2.199 + # Internal methods.
2.200 +
2.201 + def _make_container(self, parameter):
2.202 + if isinstance(parameter, (str, unicode)):
2.203 + return self.ownerDocument.createElement("string")
2.204 + elif isinstance(parameter, (int, long)):
2.205 + return self.ownerDocument.createElement("int")
2.206 + elif isinstance(parameter, float):
2.207 + return self.ownerDocument.createElement("double")
2.208 + elif isinstance(parameter, bool):
2.209 + return self.ownerDocument.createElement("boolean")
2.210 + elif isinstance(parameter, datetime.datetime):
2.211 + return self.ownerDocument.createElement("dateTime.iso8601")
2.212 +
2.213 + def _from_string(self, typename, value):
2.214 + return self.converters.get(typename, str)(value)
2.215 +
2.216 + def _item_contents(self, value):
2.217 + if value.type == "struct":
2.218 + items = []
2.219 + for member in value.container.members:
2.220 + if member.value.type == "struct":
2.221 + items.append((member.name, self._item_contents(member.value)))
2.222 + else:
2.223 + items.append((member.name, self._from_string(member.value.type, member.value.container.value)))
2.224 + return None, items
2.225 + else:
2.226 + return None, self._from_string(value.type, value.container.value)
2.227 +
2.228 + def _value_contents(self, items):
2.229 + values = []
2.230 + for name, value in items:
2.231 + if isinstance(value, list):
2.232 + values.append(self._value_contents(value))
2.233 + elif name is None:
2.234 + values.append(value)
2.235 + else:
2.236 + values.append((name, value))
2.237 return values
2.238
2.239 + def _map_contents(self, items):
2.240 + d = {}
2.241 + for n, (name, value) in enumerate(items):
2.242 + key_name = name or str(n)
2.243 + if isinstance(value, list):
2.244 + d[key_name] = self._map_contents(value)
2.245 + else:
2.246 + d[key_name] = value
2.247 + return d
2.248 +
2.249 + # Node construction methods.
2.250 +
2.251 + def createMethodName(self):
2.252 + return self.ownerDocument.createElement("methodName")
2.253 +
2.254 + def createParameters(self):
2.255 + return self.ownerDocument.createElement("params")
2.256 +
2.257 def createFault(self):
2.258 return self.ownerDocument.createElement("fault")
2.259
2.260 fault = property(_fault)
2.261 + name = property(_name, _setName)
2.262 methodName = property(_methodName)
2.263 parameters = property(_parameters)
2.264 - parameterValues = property(_parameterValues)
2.265 + parameterItems = property(_parameterItems)
2.266 + parameterValues = property(_parameterValues, _setParameterValues)
2.267 + parameterMap = property(_parameterMap)
2.268
2.269 class XMLRPCStringElement(XMLRPCNode):
2.270
2.271 @@ -158,6 +346,23 @@
2.272
2.273 value = property(_value, _setValue)
2.274
2.275 +class XMLRPCValueElement(XMLRPCStringElement):
2.276 +
2.277 + "An XML-RPC value element."
2.278 +
2.279 + def _type(self):
2.280 + elements = self.xpath("*")
2.281 + if elements:
2.282 + return elements[0].localName
2.283 + else:
2.284 + return "string"
2.285 +
2.286 + def _container(self):
2.287 + return (self.xpath("*") or [self])[0]
2.288 +
2.289 + type = property(_type)
2.290 + container = property(_container)
2.291 +
2.292 class XMLRPCMethodNameElement(XMLRPCStringElement):
2.293
2.294 "An XML-RPC method element."
2.295 @@ -208,10 +413,14 @@
2.296 "An XML-RPC structure member element."
2.297
2.298 def _name(self):
2.299 - return self.xpath("./name")[0].textContent.strip()
2.300 + value = self.xpath("./name")
2.301 + if value:
2.302 + return value[0].textContent.strip()
2.303 + else:
2.304 + return None
2.305
2.306 def _value(self):
2.307 - return self.xpath("./value")[0]
2.308 + return (self.xpath("./value") or [None])[0]
2.309
2.310 name = property(_name)
2.311 value = property(_value)
2.312 @@ -221,10 +430,18 @@
2.313 "An XML-RPC fault element."
2.314
2.315 def _code(self):
2.316 - return self.xpath("./value/struct/member[./name/text() = 'faultCode']/value/int")[0]
2.317 + code = self.xpath("./value/struct/member[./name/text() = 'faultCode']/value/int")
2.318 + if code:
2.319 + return code[0].value
2.320 + else:
2.321 + return None
2.322
2.323 def _reason(self):
2.324 - return self.xpath("./value/struct/member[./name/text() = 'faultString']/value/string")[0]
2.325 + reason = self.xpath("./value/struct/member[./name/text() = 'faultString']/value/string")
2.326 + if reason:
2.327 + return reason[0].value
2.328 + else:
2.329 + return None
2.330
2.331 code = property(_code)
2.332 reason = property(_reason)
2.333 @@ -235,7 +452,13 @@
2.334 createDocumentType = libxml2dom.createDocumentType
2.335
2.336 def createXMLRPCMessage(namespaceURI, localName):
2.337 - return default_impl.createXMLRPCMessage(namespaceURI, localName)
2.338 + return default_impl.createXMLRPCMessage(None, localName)
2.339 +
2.340 +def createMethodCall():
2.341 + return default_impl.createMethodCall()
2.342 +
2.343 +def createMethodResponse():
2.344 + return default_impl.createMethodResponse()
2.345
2.346 def parse(stream_or_string, html=0, htmlencoding=None, unfinished=0, impl=None):
2.347 return libxml2dom.parse(stream_or_string, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl))