SUDS不将响应解析为数组(只返回第一个条目)
使用SUDS库向SOAP网络服务发送请求时,应该返回一个数组,里面包含多个EnvelopeType
实例(别问我这个类型名字怎么来的)。但是现在只解析并返回了数组中的第一个条目。响应的wsdl:type
定义如下:
<wsdl:types>
<xs:element name="ShipmentsSearchDFURes">
<xs:annotation>
<xs:documentation>Comment describing your root element</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="ZEnvelope" type="dfu:EnvelopeType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</wsdl:types>
然后,使用client.last_received()
获得的原始XML响应是:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope>
<soap:Body>
<ns11:ShipmentsSearchDFURes>
<Envelope Version="2.2">
<FileInfos FileID="1" FileTime="16:10:13.110+02:00" FileDate="2014-06-18+02:00" />
<Data>
<!-- ... Omitted for brevity ... -->
</Data>
</Envelope>
<Envelope Version="2.2">
<FileInfos FileID="2" FileTime="16:12:13.117+02:00" FileDate="2014-06-18+02:00"/>
<Data>
<!-- ... -->
</Data>
</Envelope>
</ns11:ShipmentsSearchDFURes>
</soap:Body>
</soap:Envelope>
我并不是SOAP方面的专家,但我本来期待调用
client.service.ShipmentsSearch(...)
会返回一个数组,里面有多个EnvelopeType
实例,但现在只返回了第一个条目,也就是FileID="1"
的那个。也就是说,应该返回的内容是:
[envelope_1, envelope_2]
但我只得到了envelope_1
。非常感谢任何帮助。
注意 #1:我只是这个WebService的使用者。
注意 #2:PHP的SOAP客户端确实返回了一个包含多个EnvelopeType
实例的数组。是不是SUDS出了什么问题?或者是WSDL有问题?
1 个回答
0
部分解析的问题可以部分归咎于错误的类型定义,因为
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="ZEnvelope" type="dfu:EnvelopeType"/>
</xs:sequence>
应该改成:
<xs:sequence>
<xs:element name="ZEnvelope" type="dfu:EnvelopeType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
根据W3.org上的XML Schema。使用本地的WSDL文件和里面引用的文件,并做上述修改,可以解决这个问题。
如果你想知道,当解析原始的XML响应时,SUDS会使用XSD模式,而导致解析不好的根本原因是因为在Binding.get_reply()
方法的第158到161行对根节点的处理有点过于严格:
130 def get_reply(self, method, reply):
131 """
132 Process the I{reply} for the specified I{method} by sax parsing the I{reply}
133 and then unmarshalling into python object(s).
134 @param method: The name of the invoked method.
135 @type method: str
136 @param reply: The reply XML received after invoking the specified method.
137 @type reply: str
138 @return: The unmarshalled reply. The returned value is an L{Object} for a
139 I{list} depending on whether the service returns a single object or a
140 collection.
141 @rtype: tuple ( L{Element}, L{Object} )
142 """
143 reply = self.replyfilter(reply)
144 sax = Parser()
145 replyroot = sax.parse(string=reply)
146 plugins = PluginContainer(self.options().plugins)
147 plugins.message.parsed(reply=replyroot)
148 soapenv = replyroot.getChild('Envelope')
149 soapenv.promotePrefixes()
150 soapbody = soapenv.getChild('Body')
151 self.detect_fault(soapbody)
152 soapbody = self.multiref.process(soapbody)
153 nodes = self.replycontent(method, soapbody)
154 rtypes = self.returned_types(method)
155 if len(rtypes) > 1:
156 result = self.replycomposite(rtypes, nodes)
157 return (replyroot, result)
158 if len(rtypes) == 1:
159 if rtypes[0].unbounded():
160 result = self.replylist(rtypes[0], nodes)
161 return (replyroot, result)
162 if len(nodes):
163 unmarshaller = self.unmarshaller()
164 resolved = rtypes[0].resolve(nobuiltin=True)
165 result = unmarshaller.process(nodes[0], resolved)
166 return (replyroot, result)
167 return (replyroot, None)
在这里,作者完全依赖于类型定义,而不考虑nodes
列表的大小。具体来说,我认为第159行的测试应该改成:
158 if len(rtypes) == 1:
159 if rtypes[0].unbounded() or len(nodes)>1:
160 result = self.replylist(rtypes[0], nodes)
161 return (replyroot, result)
也许还应该加个警告,提示XSD和实际响应之间的不匹配。希望这对你有帮助。