中国开发网: 论坛: 程序员情感CBD: 贴子 328786
haitao
尽管我们访问飞机票价 Web 服务的努力是令人沮丧的。。。这里的问题很大一部分在于,当您走出平凡 Web 服务领域时,SOAP 就太复杂了
尽管我们访问飞机票价 Web 服务的努力是令人沮丧的,但是我们可以看到 ZSI 和 SOAPpy 取得了重大的进展。在这些文章中我们的目的并不是贬低这些建议,而是展示我们落入的陷阱,以便其他人可以避开它们。我们认为这里的问题很大一部分在于,当您走出平凡 Web 服务领域时,SOAP 就太复杂了。正如我们提到的,人们逐渐接受的文档/文字(document/literal)编码将数据体系结构的问题缩小到我们在 XML 中已经得到了很好的理解的问题。幸运的是,您可以实现很多,而又不用闯入混乱的复杂结构类型。在最近的文章中,我们已经成功地使用 SOAPpy (而且某些测试说明 ZSI 也将起作用)访问了 Google 和 Amazon.com 的 Web 服务 API。甚至这些商业服务都避免复杂的结构类型。飞机票价报价服务仅仅接受简单的定位参数是没有理由的。对于遇到的大部分 SOAP 任务,您应该能够使用 ZSI 和 SOAPpy,但是认识到它们的局限也很重要。

http://www-128.ibm.com/developerworks/cn/webservices/ws-pyth17.html

Python Web 服务开发者: Python SOAP 库,第 5 部分
SOAPpy 的新开发


文档选项
将此页作为电子邮件发送



最新推荐
Java 应用开发源动力 - 下载免费软件,快速启动开发




级别: 初级

Scott Archer, 软件架构师, GlowingOrb, Inc.
Uche Ogbuji, 首席顾问, Fourthought, Inc.


2004 年 4 月 01 日

如同它的姊妹项目 ZSI 一样,SOAPpy 近来逐渐活跃,现在已经是版本 0.11.3。这个版本包括 WSDL 支持和很多其他的改进。Uche Ogbuji 和 Scott Archer 试用了这个新的版本(他们使用的 Web 服务与以前曾通过 ZSI 1.4.1 访问的 Web 服务的复杂程度是一样的),并且碰到了一些不同的困难。
在前两期中(请参阅 参考资料),我们了解了最新的 ZSI,也就是过去介绍的 Python Web 服务库。这个月,我们将着眼于另外一个这样的库的更新。SOAPpy 是“Web Services for Python”项目的另外一个组件。版本 0.11.3 是最新的,并且如同 ZSI,最新的一组版本添加了一系列给人印象深刻的改进和补充。我们同样也已经在我们最近关于实际的 Web 服务的文章中使用 SOAPpy 来访问 Google 和 Amazon 的 Web 服务。(请参阅 参考资料)。

安装软件


我们下载了在 Python 2.3.3 中安装的 SOAPpy 0.11.3,但是在安装它以前,我们必须下载并安装下列必备软件:

fpconst--专门处理 IEEE 754 浮点数的 Python 库。版本 0.6.0 或更新的 fpconst 是 SOAPpy 新的先决条件。我们安装了 0.6.0。
pyXML0.8.3 或更新的版本同样也是必需的。
可以使用当前标准的 python setup.py install 从解压缩目录很好地安装这个软件。您也可以安装下面的软件以便启用特殊的功能。然而,我们没有选择安装这个软件。

pyGlobus用于启用对用于网格计算的 Globus Alliance toolkit 的支持(目前是 Globus toolkit 的 2.2.4 和 2.4 版本必不可少的一部分)。
M2Crypto.SSL用来启用对 SOAP 服务器上的 SSL 的支持。为了启用 SOAP 客户端对 SSL 的支持,您需要 SSL 支持编译成 Python。这是 Python 2.3+ 缺省设置的。





回页首




WSDL 和更多的 dateTime 问题


与 ZSI 一样,SOAPpy 最近的特征是 WSDL 支持。在 SOAPpy 中用于 SOAP 访问底层 API 是相当容易使用的,但是 WSDL 承诺使用更少的建立(set-up)代码。

我们尝试调用一个 Web 服务,这个 Web 服务使用 ZSI 1.4.1 会给我们造成一些困难。正如我们在上篇文章中(Python SOAP 库,第 4 部分)所介绍的:


Richard Hastings 的 Air Fare Quote Search 是在 Apache Axis 中实现的,并且实时地查询一些航空公司的 Web 站点来寻找特定航线最合适的班机票价(请参阅 参考资料)。它聚集并返回根据价钱排序的结果。这个 WSDL 位于 http://wavendon.dsdata.co.uk:8080/axis/services/SBGGetAirFareQuote?wsdl。它定义了两个操作: getAirFareQuote 和 getAirlines 。前者用来执行价钱查询,它有四个参数:两个 W3C XML Schema Language Data Types (WXSDT) dateTime 值(给出航班大致的起飞和返回时间)以及两个 WXSDT string 值(给出飞行起点和终点之间飞机场的三个字母的代码)。
建立(set-up)代码是足够直接了当的:




>>> import SOAPpy
>>> wsdl = 'http://wavendon.dsdata.co.uk:8080\\
... /axis/services/SBGGetAirFareQuote?wsdl'
>>> proxy = SOAPpy.WSDL.Proxy(wsdl)





我们尝试直接的位置参数方法调用,我们已经使用 ZSI 试过。我们已经输入了两个 dateTime 参数,在两个字符串参数之后,正好用于 getAirFareQuote 方法调用。所以,我们已经解决了如何创建 dateTime 类型的问题。文档 docs/simpleTypes.txt 建议创建 SOAP.DateTime 的实例,但是这给出了 AttributeError 。结果,我们不得不使用 SOAP.dateTimeType 。这采用一个 Python 时间元组(time tuple)。为了可读性,我们由 ISO-8601 字符串创建这个元组,并且挑选参数为我们提供即将去美国华盛顿(Washington,D.C.,USA)的 PyCon 旅行的费用。



>>> proxy.getAirFareQuote(SOAPpy.dateTimeType(dep), SOAPpy.dateTimeType(ret), 'den', 'phl')
>>> import time
>>> ISO_8601_DATETIME = '%Y-%m-%dT%H:%M:%S'
>>> dep = time.strptime('2004-03-24T12:30:59', ISO_8601_DATETIME)
>>> dep_dt = SOAPpy.dateTimeType(dep)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/home/uogbuji/lib/lib/python2.3/site-packages/SOAPpy/Types.py", line 79, in __init__
self._data = self._checkValueSpace(data)
File "/home/uogbuji/lib/lib/python2.3/site-packages/SOAPpy/Types.py",
line 442, in _checkValueSpace
raise ValueError, "invalid %s value - %s" % (self._type, e)
ValueError: invalid dateTime value - invalid type
>>>





在调试这个相当隐讳的错误的试验和出错之后,我们了解到 SOAPpy 并不像 Python 时间元组(time tuples)在 tm_isdst 字段带有 -1 。在使用这个值的时候,它通常说明用户想要用这个库来处理使用敏感的缺省夏令时(daylight savings time)。因为 SOAPpy 不能处理 Python 时间元组(time tuples),我们不得不强制所有的都遵从格林尼治标准时间(Greenwich Mean Time,GMT)。






回页首




我们需要一些结构


在将日期调整为使用 GMT 以后,我们最终能够与远程服务器联系:




>>> import time
>>> dep = SOAPpy.dateTimeType((2004, 3, 24, 12, 30, 59, 4, 86, 0))
>>> ret = SOAPpy.dateTimeType((2004, 3, 26, 12, 30, 59, 4, 86, 0))
>>> proxy.getAirFareQuote(dep, ret, 'den', 'iad')



... Long, bewildering SOAP fault snipped ...





Python 的 time.strptime 已经成为很多开发人员想当然滥用的主题,它没有办法处理合适的 ISO 8601 时区间隔。最接近的格式指定符 %Z 只接受国内的时区名称,比如 MST,这在 ISO-8601 中是不允许的。最后,我们仅仅是直接使用麻烦的时间元组(time tuples)。我们曾经构造了一个 SOAP 消息并发送给了服务器。在最近本文发表之前,我们还不能使用 ZSI 来这样做( 单击这里以获得更新)。不幸的是,服务器并不那么热心的。它发送回一个极其难懂的 SOAP 错误--一个巨大的 Java 堆栈跟踪,其中的关键行是: org.xml.sax.SAXException: No such operation 'getAirFareQuote。我们知道这个错误消息有一些可疑,因为我们可以使用在线的 SOAP 调试器来访问 getAirFareQuote 方法。实际上,如果我们尝试做一些实验:




>>> proxy.getAirFareQuote()
[]
>>>





我们确实得到了结果。错误消息是“我不理解您调用这个方法的方式”,这是一种难以理解的表述。通过 Google 检索的一些资料带来这样一条线索,就是我们应该更进一步地阅读 WSDL。服务器其实期望在称作 in0 的结构中定义多引用(multi-ref),包括我们已经直接传送的四个参数。所以,我们需要处理结构类型。文档 docs/complexTypes.txt 对于寻找如何完成这项工作的方法根本没有帮助。我们不得不钻研 SOAPpy 代码来寻找我们所需要的合适的类, SOAPpy.structType() 。我们做了这样一些实验:




>>> in0 = SOAPpy.structType()
>>> in0._addItem('outwardDate', dep)
>>> in0._addItem('returnDate', ret)
>>> in0._addItem('originAirport', 'den')
>>> in0._addItem('destinationAirport', 'iad')





这次我们得到了不同的 SOAP 错误--一个 Java Traceback,带有初始消息 org.xml.sax.SAXException: No deserializer defined for array type {http://www.w3.org/1999/XMLSchema}ur-type。现在是查看 WSDL 实际上在线路上发送什么的时候了。我们启动 SOAPpy 的调试工具。幸运的是,与 SOAPpy 的 0.9x 版本不同,有一种简单的开启和关闭调试代码的方法,即将 SOAPpy.Config.debug 设置为 0 或 1。




>>> SOAPpy.Config.debug = 1
>>> proxy.getAirFareQuote(in0)





这引出大量的文本,但是我们发现出站的 SOAP 负载隐藏在输出中。



*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd3="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getAirFareQuote
xmlns:ns1="urn:SBGAirFareQuotes.sbg.travel.ws.dsdata.co.uk"
SOAP-ENC:root="1">
<v1 href="#i1"/>
</ns1:getAirFareQuote>
<xsd:v1 id="i1" SOAP-ENC:root="0">
<outwardDate href="#i2"/>
<returnDate href="#i3"/>
<originAirport href="#i4"/>
<destinationAirport href="#i5"/>
</xsd:v1>
<outwardDate SOAP-ENC:arrayType="xsd:ur-type[4]" xsi:type="SOAP-ENC:Array"
SOAP-ENC:root="0" id="i2">
<item href="#i3"/>
<item href="#i3"/>
<item href="#i4"/>
<item href="#i5"/>
</outwardDate>
<returnDate xsi:type="xsd3:dateTime" id="i3"
SOAP-ENC:root="0">2004-03-24T12:30:59Z</returnDate>
<originAirport xsi:type="xsd:string" id="i4"
SOAP-ENC:root="0">den</originAirport>
<destinationAirport SOAP-ENC:arrayType="xsd:string[2]"
xsi:type="SOAP-ENC:Array" SOAP-ENC:root="0" id="i5">
<item href="#i6"/>
<item href="#i7"/>
</destinationAirport>
<item xsi:type="xsd:string" id="i6" SOAP-ENC:root="0">phl</item>
<item xsi:type="xsd:string" id="i7" SOAP-ENC:root="0">iad</item>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
************************************************************************





出于编排格式方面的原因,我们已经添加了一些新行和缩进。很明显,这完全是添乱。W3C XML Schema 名称空间和基本数据结构来自于 SOAP 提议的废弃很久的版本。很难想象在没有大量工作的情况下,如何将它转换成当前 SOAP 实现可以识别的事物。搜索 SOAPpy 代码以查找可能有帮助的标记和选项并没有找到任何鼓舞人心的东西。此刻,我们放弃了试图访问飞机票价报价服务。当然,我们可以足够容易地访问 getAirlines 方法:




>>> SOAPpy.Config.debug = 0
>>> proxy.getAirlines()
['Alitalia', 'American Airlines', 'BMI', 'BMIBaby', 'British Airways',
'Continental', 'EasyJet', 'EBookers', 'Expedia', 'Global Traveller',
'Lufthansa', 'Northwest Airlines', 'Maersk Air', 'Opodo', 'Qantas',
'Ryanair', 'Star Alliance', 'Travelocity', 'United']
>>>





当然,这又回到了我们曾经希望越过的 Web 服务的微不足道的特点。WSDL 模块 SOAPpy 和 ZSI 受欢迎的增加,因为它简化了解决服务的底层细节的流程。然而,如果您需要复杂的数据结构编组,而 Python SOAP 实现好像还没有跟上的时候,它并没有任何帮助。此外,我们想要强调,这是对 SOAP RPC 复杂类型极端神秘的控诉。这是整个 SOAP 社区急待解决的问题。幸运的是,随着 SOAP 的文档/文字(document/literal)特点的出现,已经有了一些希望。






回页首




ZSI 更新


在我们上篇文章发表之后,ZSI 的核心开发人员 Rich Salz 发来一封电子邮件指出:


有时, time.strptime() 的返回值会发生从元组到 <type 'time.struct_time'> 的改变。[...]下面的片断--注意 tuple() 调用 dep 和 ret --[达到]更进一步。
ZSI bug?Python 发展得太迅速?你的理由 ...
我们试验了他提出经过修改的代码:




>>> from ZSI import ServiceProxy
>>> wsdl = 'http://wavendon.dsdata.co.uk:8080\\
... /axis/services/SBGGetAirFareQuote?wsdl'
>>> proxy = ServiceProxy(wsdl)
>>> import time
>>> ISO_8601_DATETIME = '%Y-%m-%dT%H:%M:%S'
>>> dep = tuple(time.strptime('2003-12-06T12:30:59', ISO_8601_DATETIME))
>>> ret = tuple(time.strptime('2003-12-12T12:30:59', ISO_8601_DATETIME))
>>> proxy.getAirFareQuote(dep, ret, 'den', 'phl')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/home/uogbuji/lib/lib/python2.3/site-packages/ZSI/ServiceProxy.py",
line 82, in __call__
return self.parent()._call(self.__name__, *args, **kwargs)
File "/home/uogbuji/lib/lib/python2.3/site-packages/ZSI/ServiceProxy.py",
line 65, in _call
apply(getattr(binding, callinfo.methodName), args)
File "/home/uogbuji/lib/lib/python2.3/site-packages/ZSI/client.py", line 28, in __call__
requesttypecode=TC.Any(self.name, aslist=1))
File "/home/uogbuji/lib/lib/python2.3/site-packages/ZSI/client.py", line 132, in RPC
return self.Receive(replytype, **kw)
File "/home/uogbuji/lib/lib/python2.3/site-packages/ZSI/client.py", line 261, in Receive
raise FaultException(msg)
ZSI.FaultException: org.xml.sax.SAXException: No such operation 'getAirFareQuote'
>>>





使用经过修改的代码使我们到了将 SOAP 请求传送给服务器的时刻,但是我们回到了解决如何发送远程方法期望的精确的结构。






回页首




总结


尽管我们访问飞机票价 Web 服务的努力是令人沮丧的,但是我们可以看到 ZSI 和 SOAPpy 取得了重大的进展。在这些文章中我们的目的并不是贬低这些建议,而是展示我们落入的陷阱,以便其他人可以避开它们。我们认为这里的问题很大一部分在于,当您走出平凡 Web 服务领域时,SOAP 就太复杂了。正如我们提到的,人们逐渐接受的文档/文字(document/literal)编码将数据体系结构的问题缩小到我们在 XML 中已经得到了很好的理解的问题。幸运的是,您可以实现很多,而又不用闯入混乱的复杂结构类型。在最近的文章中,我们已经成功地使用 SOAPpy (而且某些测试说明 ZSI 也将起作用)访问了 Google 和 Amazon.com 的 Web 服务 API。甚至这些商业服务都避免复杂的结构类型。飞机票价报价服务仅仅接受简单的定位参数是没有理由的。对于遇到的大部分 SOAP 任务,您应该能够使用 ZSI 和 SOAPpy,但是认识到它们的局限也很重要。






回页首




参考资料

您可以参阅本文在 developerWorks 全球站点上的 英文原文.


请参与本文的 论坛。(您同样也可以单击本文顶部或底部的 讨论来访问论坛。)




Python SOAP 库,第 4 部分讨论了 ZSI V1.4.1 及其附加的对 WSDL 的支持。




在 现实世界,第一部分中,我们了解了在 Python 中如何访问 Google 的 Web 服务,而 现实世界,第二部分研究了 Amazon 的服务。




密切关注 Python Web Services,目前托管 ZSI 和 SOAPpy 的 SourceForge 项目。




查阅 Richard Hastings 的机票报价搜索(Richard Hastings' Air Fare Quote Search),它是在 Apache Axis 中实现的,并且实时地查询一些航空公司的 Web 站点来查找特定航线的最佳航班价格。




Weblog 入门学习资料“ Working with multirefs, Axis, and SOAP::Lite”指出,Python Web 服务实现并不是惟一使用机票报价服务有困难的。




James McCarthy 撰写的文章 “获得文档样式 Web 服务的好处”探究了 SOAP 的文档/文字类型( developerWorks,2002 年 6 月)。




请参与本文的 论坛。(您同样可以单击本文顶部或底部的 讨论来访问论坛。)




查阅 本系列中所有的 Python Web 服务开发者专栏。








回页首




作者简介



Scott Archer 是 GlowingOrb 公司的软件架构师和联合创立者、专注于模型驱动的解决方案和将它们集成到核心业务流程的软件工具开发者。Archer 拥有 University of Hong Kong 计算分子生物学哲学硕士学位。您可以通过 scott.archer@glowingorb.com与 Archer 联系。




Uche Ogbuji 是 Fourthought Inc.的顾问和联合创立者、软件经销商和专注于企业知识管理的 XML 解决方案方面的顾问。Fourthought 开发了 4Suite,一个用于 XML、RDF 和知识管理应用程序的开放源代码平台。Mr. Ogbuji 也是 VersaRDF 查询语言的主要开发者。他是计算机工程师和作家,生于 Nigeria,生活和工作在 Boulder,Colorado,USA。您可以通过 uche.ogbuji@fourthought.com与 Ogbuji 联系。
我的blog:http://szhaitao.blog.hexun.com & http://www.hoolee.com/user/haitao
--以上均为泛泛之谈--
不尽牛人滚滚来,无边硬伤纷纷现 人在江湖(出来的),哪能不挨刀(总归是要的)
网络对话,歧义纷生;你以为明白了对方的话,其实呢?

您所在的IP暂时不能使用低版本的QQ,请到:http://im.qq.com/下载安装最新版的QQ,感谢您对QQ的支持和使用

相关信息:


欢迎光临本社区,您还没有登录,不能发贴子。请在 这里登录