1.1 --- a/libxml2dom/soap.py Sun Oct 07 13:48:50 2007 +0000
1.2 +++ b/libxml2dom/soap.py Sun Oct 07 14:31:15 2007 +0000
1.3 @@ -1,7 +1,8 @@
1.4 #!/usr/bin/env python
1.5
1.6 """
1.7 -SOAP support using libxml2dom.
1.8 +SOAP support using libxml2dom. Support for the archaic SOAP namespaces is also
1.9 +provided.
1.10
1.11 See: http://www.w3.org/TR/2007/REC-soap12-part0-20070427/
1.12
1.13 @@ -41,6 +42,11 @@
1.14 XS_NAMESPACE = "http://www.w3.org/2001/XMLSchema"
1.15 XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
1.16
1.17 +# Archaic namespaces.
1.18 +
1.19 +OLD_SOAP_ENVELOPE_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/"
1.20 +OLD_SOAP_ENCODING_NAMESPACE = "http://schemas.xmlsoap.org/soap/encoding/"
1.21 +
1.22 # Default namespace bindings for XPath.
1.23
1.24 default_ns = {
1.25 @@ -48,7 +54,9 @@
1.26 "enc" : SOAP_ENCODING_NAMESPACE,
1.27 "rpc" : SOAP_RPC_NAMESPACE,
1.28 "xs" : XS_NAMESPACE,
1.29 - "xsi" : XSI_NAMESPACE
1.30 + "xsi" : XSI_NAMESPACE,
1.31 + "SOAP-ENV" : OLD_SOAP_ENVELOPE_NAMESPACE,
1.32 + "SOAP-ENC" : OLD_SOAP_ENCODING_NAMESPACE
1.33 }
1.34
1.35 class SOAPImplementation(libxml2dom.Implementation):
1.36 @@ -73,7 +81,7 @@
1.37
1.38 # Make special envelope elements.
1.39
1.40 - if Node_namespaceURI(_node) == SOAP_ENVELOPE_NAMESPACE:
1.41 + if Node_namespaceURI(_node) in (SOAP_ENVELOPE_NAMESPACE, OLD_SOAP_ENVELOPE_NAMESPACE):
1.42 if Node_localName(_node) == "Envelope":
1.43 return SOAPEnvelopeElement(_node, self, context_node.ownerDocument)
1.44 elif Node_localName(_node) == "Header":
1.45 @@ -94,7 +102,7 @@
1.46 # Detect the method element.
1.47
1.48 if Node_parentNode(_node) and Node_localName(Node_parentNode(_node)) == "Body" and \
1.49 - Node_namespaceURI(Node_parentNode(_node)) == SOAP_ENVELOPE_NAMESPACE:
1.50 + Node_namespaceURI(Node_parentNode(_node)) in (SOAP_ENVELOPE_NAMESPACE, OLD_SOAP_ENVELOPE_NAMESPACE):
1.51
1.52 return SOAPMethodElement(_node, self, context_node.ownerDocument)
1.53
1.54 @@ -138,45 +146,65 @@
1.55 return node.textContent.strip()
1.56
1.57 def _contents(self):
1.58 + # NOTE: Should check whether this should be a leaf element.
1.59 if not self.xpath("*"):
1.60 return (self.localName, getattr(self.ownerDocument, "convert", self.convert)(self))
1.61 else:
1.62 - return self
1.63 + return (self.localName, SOAPContents(self))
1.64
1.65 def __len__(self):
1.66 - children = self.xpath("*")
1.67 - if not children:
1.68 - return 2
1.69 - else:
1.70 - return len(children)
1.71 + return 2
1.72
1.73 def __getitem__(self, i):
1.74 - children = self.xpath("*")
1.75 - if not children:
1.76 - return self.contents[i]
1.77 - else:
1.78 - return self.xpath("*")[i]
1.79 + return self.contents[i]
1.80
1.81 def __eq__(self, other):
1.82 - children = self.xpath("*")
1.83 - if children:
1.84 - for i, j in map(None, self, other):
1.85 - if i != j:
1.86 - return False
1.87 - return True
1.88 - elif hasattr(other, "contents"):
1.89 + if hasattr(other, "contents"):
1.90 return self.contents == other.contents
1.91 else:
1.92 return self.contents == other
1.93
1.94 + # Node construction methods.
1.95 +
1.96 + def createSOAPElement(self, localName):
1.97 +
1.98 + "Create an element with the appropriate namespace and prefix."
1.99 +
1.100 + ref_element = self.ownerDocument.documentElement
1.101 + prefix = ref_element.prefix
1.102 + if prefix:
1.103 + name = prefix + ":" + localName
1.104 + else:
1.105 + name = localName
1.106 + return self.createElementNS(ref_element.namespaceURI, name)
1.107 +
1.108 contents = property(_contents)
1.109
1.110 +class SOAPContents(object):
1.111 +
1.112 + "A wrapper around another node in order to provide sequence-like access."
1.113 +
1.114 + def __init__(self, node):
1.115 + self.node = node
1.116 +
1.117 + def __len__(self):
1.118 + return len(self.node.xpath("*"))
1.119 +
1.120 + def __getitem__(self, i):
1.121 + return self.node.xpath("*")[i]
1.122 +
1.123 + def __eq__(self, other):
1.124 + for i, j in map(None, self, other):
1.125 + if i != j:
1.126 + return False
1.127 + return True
1.128 +
1.129 class SOAPDocument(libxml2dom._Document, SOAPNode):
1.130
1.131 "A SOAP document fragment."
1.132
1.133 def _envelope(self):
1.134 - return self.xpath("./env:Envelope")[0]
1.135 + return self.xpath("env:Envelope|SOAP-ENV:Envelope")[0]
1.136
1.137 envelope = property(_envelope)
1.138
1.139 @@ -202,7 +230,7 @@
1.140 "A SOAP envelope element."
1.141
1.142 def _body(self):
1.143 - return self.xpath("./env:Body")[0]
1.144 + return self.xpath("env:Body|SOAP-ENV:Body")[0]
1.145
1.146 def _setBody(self, body):
1.147 self.appendChild(body)
1.148 @@ -211,7 +239,7 @@
1.149 self.removeChild(self.body)
1.150
1.151 def createBody(self):
1.152 - return self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Body")
1.153 + return self.createSOAPElement("Body")
1.154
1.155 body = property(_body, _setBody, _delBody)
1.156
1.157 @@ -226,15 +254,18 @@
1.158 "A SOAP body element."
1.159
1.160 def _fault(self):
1.161 - return (self.xpath("./env:Fault") or [None])[0]
1.162 + return (self.xpath("env:Fault|SOAP-ENV:Fault") or [None])[0]
1.163
1.164 def _method(self):
1.165 - return (self.xpath("./*[@env:encodingStyle = '%s']" % SOAP_ENCODING_NAMESPACE) or [None])[0]
1.166 + if self.namespaceURI == SOAP_ENVELOPE_NAMESPACE:
1.167 + return (self.xpath("*[@env:encodingStyle = '%s']" % SOAP_ENCODING_NAMESPACE) or [None])[0]
1.168 + else:
1.169 + return (self.xpath("*") or [None])[0]
1.170
1.171 # Node construction methods.
1.172
1.173 def createFault(self):
1.174 - return self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Fault")
1.175 + return self.createSOAPElement("Fault")
1.176
1.177 fault = property(_fault)
1.178 method = property(_method)
1.179 @@ -273,27 +304,27 @@
1.180 "A SOAP fault element."
1.181
1.182 def _code(self):
1.183 - code = self.xpath("./env:Code")
1.184 + code = self.xpath("env:Code|SOAP-ENV:Code")
1.185 if code:
1.186 return code[0].value
1.187 else:
1.188 return None
1.189
1.190 def _subcode(self):
1.191 - subcode = self.xpath("./env:Code/env:Subcode")
1.192 + subcode = self.xpath("./env:Code/env:Subcode|./SOAP-ENV:Code/SOAP-ENV:Subcode")
1.193 if subcode:
1.194 return subcode[0].value
1.195 else:
1.196 return None
1.197
1.198 def _reason(self):
1.199 - return (self.xpath("./env:Reason") or [None])[0]
1.200 + return (self.xpath("env:Reason|SOAP-ENV:Reason") or [None])[0]
1.201
1.202 def _detail(self):
1.203 - return (self.xpath("./env:Detail") or [None])[0]
1.204 + return (self.xpath("env:Detail|SOAP-ENV:Detail") or [None])[0]
1.205
1.206 def createCode(self):
1.207 - return self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Code")
1.208 + return self.createSOAPElement("Code")
1.209
1.210 code = property(_code)
1.211 subcode = property(_subcode)
1.212 @@ -305,14 +336,14 @@
1.213 "A SOAP subcode element."
1.214
1.215 def _value(self):
1.216 - value = self.xpath("./env:Value")
1.217 + value = self.xpath("env:Value|SOAP-ENV:Value")
1.218 if value:
1.219 return value[0].textContent.strip()
1.220 else:
1.221 return None
1.222
1.223 def _setValue(self, value):
1.224 - nodes = self.xpath("./env:Value")
1.225 + nodes = self.xpath("env:Value|SOAP-ENV:Value")
1.226 v = self.createValue()
1.227 if nodes:
1.228 self.replaceChild(v, nodes[0])
1.229 @@ -321,7 +352,7 @@
1.230 v.value = value
1.231
1.232 def createValue(self, value=None):
1.233 - code_value = self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Value")
1.234 + code_value = self.createSOAPElement("Value")
1.235 if value is not None:
1.236 code_value.value = code
1.237 return code_value
1.238 @@ -333,10 +364,10 @@
1.239 "A SOAP code element."
1.240
1.241 def _subcode(self):
1.242 - return (self.xpath("./env:Subcode") or [None])[0]
1.243 + return (self.xpath("env:Subcode|SOAP-ENV:Subcode") or [None])[0]
1.244
1.245 def createSubcode(self):
1.246 - return self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Subcode")
1.247 + return self.createSOAPElement("Subcode")
1.248
1.249 subcode = property(_subcode)
1.250