12.6. 以 WSDL 进行 SOAP 内省
Description: Python from novice to pro
Keywords: Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free

# 深入 Python :Dive Into Python 中文版 Python 从新手到专家 [Dip_5.4b_CPyUG_Release] | Find:

## 12.6. 以 WSDL 进行 SOAP 内省

就像网络服务舞台上的所有事物，WSDL 也经历了一个充满明争暗斗而且漫长多变的历史。我不打算讲述这段令我伤心的历史。还有一些其他的标准提供相同的支持，但 WSDL 还是胜出，所以我们还是来学习一下如何使用它。

WSDL 最基本的功能便是让你揭示 SOAP 服务器所提供的有效方法。

### 例 12.8. 揭示有效方法

    >>> from SOAPpy import WSDL
    >>> wsdlFile = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl'
    >>> server = WSDL.Proxy(wsdlFile)
    >>> server.methods.keys()
    [u'getTemp']

| SOAPpy 包含一个 WSDL 解析器。在本书写作之时，它被标示为开发的初级阶段，但我从来没有在解析任何 WSDL 文件时遇到问题。
| 使用一个 WSDL 文件，你还是要用到一个 proxy 类：`WSDL.Proxy`，它只需一个参数：WSDL 文件。我指定的是存储在远程服务器上的 WSDL 的 URL，但是这个 proxy 类对于本地的 WSDL 副本工作同样出色。创建 WSDL proxy 将会下载 WSDL 文件并解析它，所以如果 WSDL 文件有任何问题 (或者由于网络问题不能获得) 你会立刻知道。
| WSDL proxy 类通过 Python 字典 `server.methods` 揭示有效函数。所以列出有效方法只需调用字典方法 `keys()`。

好的，你知道这个 SOAP 服务器提供一个方法：`getTemp`。但是如何去调用它呢？WSDL 也在这方面提供信息。

### 例 12.9. 揭示一个方法的参数

    >>> callInfo = server.methods['getTemp']
    >>> callInfo.inparams
    [<SOAPpy.wstools.WSDLTools.ParameterInfo instance at 0x00CF3AD0>]
    >>> callInfo.inparams[0].name
    u'zipcode'
    >>> callInfo.inparams[0].type
    (u'http://www.w3.org/2001/XMLSchema', u'string')

| `server.methods` 字典中记录一个 SOAPpy 的特别结构，被称为 `CallInfo`。`CallInfo` 对象中包含着特定函数和函数参数的信息。
| 函数参数信息存储在 `callInfo.inparams` 中，这是一个记录每一个参数信息的 `ParameterInfo` 对象的 Python 列表。
| 每个 `ParameterInfo` 对象包含一个 `name` 属性，这便是参数名。在通过 SOAP 调用函数时，你不需要知道参数名，但 SOAP 支持在调用函数时使用参数名 (类似于 Python)。如果使用参数名，`WSDL.Proxy` 将会正确地把这些参数关联到远程函数。
| 每个参数都是都是显式类型的，使用的是在 XML Schema 定义的数据类型。你可以在上一节中发现这一点：XML Schema 命名空间是我让你忽略的模版的一部分。就目前而言，你还是可以继续忽略它。`zipcode` 参数是一个字符串，如果你向 `WSDL.Proxy` 对象传递一个 Python 字符串，它会被正确地关联和传递到服务器。

WSDL 还允许你自省函数的返回值。

### 例 12.10. 揭示方法返回值

    >>> callInfo.outparams
    [<SOAPpy.wstools.WSDLTools.ParameterInfo instance at 0x00CF3AF8>]
    >>> callInfo.outparams[0].name
    u'return'
    >>> callInfo.outparams[0].type
    (u'http://www.w3.org/2001/XMLSchema', u'float')

| 与揭示函数参数的 `callInfo.inparams` 对应的是揭示返回值的 `callInfo.outparams`。它也同样是一个列表，因为通过 SOAP 调用函数时可以返回多个值，就像 Python 函数一样。
| `ParameterInfo` 对象包含 `name` 和 `type`。这个函数返回一个浮点值，它的名字是 `return`。

让我们整合一下，通过 WSDL proxy 调用一个 SOAP 网络服务。

### 例 12.11. 通过 WSDL proxy 调用一个 SOAP 网络服务

    >>> from SOAPpy import WSDL
    >>> wsdlFile = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl')
    >>> server = WSDL.Proxy(wsdlFile)
    >>> server.getTemp('90210')
    66.0
    >>> server.soapproxy.config.dumpSOAPOut = 1
    >>> server.soapproxy.config.dumpSOAPIn = 1
    >>> temperature = server.getTemp('90210')
    *** 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:xsd="http://www.w3.org/1999/XMLSchema">
    <SOAP-ENV:Body>
    <ns1:getTemp xmlns:ns1="urn:xmethods-Temperature" SOAP-ENC:root="1">
    <v1 xsi:type="xsd:string">90210</v1>
    </ns1:getTemp>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    ************************************************************************
    *** Incoming SOAP ******************************************************
    <?xml version='1.0' encoding='UTF-8'?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <SOAP-ENV:Body>
    <ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature"
      SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <return xsi:type="xsd:float">66.0</return>
    </ns1:getTempResponse>

    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    ************************************************************************

    >>> temperature
    66.0

| 这比直接调用 SOAP 服务时的设置简单，因为在 WSDL 文件中包含着调用服务所需要的服务 URL 和命名空间。创建 `WSDL.Proxy` 对象将会下载 WSDL 文件，解析之，并设置一个用以调用实际的 SOAP 网络服务的 `SOAPProxy` 对象。
| 只要创建了 `WSDL.Proxy` 对象，你就可以像调用 `SOAPProxy` 对象一样简单地调用一个函数。这并不奇怪，`WSDL.Proxy` 就是一个具有自省方法的 `SOAPProxy` 封装套件，所以调用函数的语法也是一样的。
| 你可以通过 `server.soapproxy` 访问 `WSDL.Proxy` 的 `SOAPProxy`。这对于打开查错模式很重要，这样一来当你通过 WSDL proxy 调用函数时，它的 `SOAPProxy` 将会把线路上来往的 XML 文档甩下来。