WSDL导入

本技巧阐明了 Web 服务描述语言(Web Services Description Language,WSDL)文件中两种类型的导入语句之间的细微差别。

 

导入 (Import)语句很简单,对吗?差不多每个程序或接口语言都用到它。当你阅读这篇技巧时,可能早已了解了关于导入的所有知识。那么,为什么要阅读这篇 关于 Web 服务描述语言(Web Services Description Language,WSDL)文件导入的技巧呢?首先,import 语句有两种类型:XSD 导入和 WDSL 导入。其次,这两种导入语句各自的特点不完全相同。最后,应该搞清楚这两者之间的联系。

Import 与 include

在深入描述 import 语句之前,让我们先来比较一下 import 和 include 之间的区别。import 语句引入其他的命名空间(namespace),但 include 语句却是将其他的声明引入到当前命名空间中。

 



 

XSD 导入

让我们来查看基本 XSD 导入,如清单 1 中用红色突出显示的部分所示。这部分语句做的全部事情就是将命名空间从一个模式导入到另一个模式。定义了 urn:listing2 命名空间的模式导入 urn:listing3 模式 。仅此而已,没有任何文件被导入。这两个模式都在清单 1 中的同一个文件内。


清单 1. 使用两个命名空间的地址簿 WSDL

 

<?xml version="1.0" ?>
<wsdl:definitions targetNamespace="urn:listing2"
                  xmlns:tns="urn:listing2"
                  xmlns:listing3="urn:listing3"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
    <xsd:schema targetNamespace="urn:listing3"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema">          
      <xsd:complexType name="Phone">
        <xsd:sequence>
          <xsd:element name="areaCode" type="xsd:int"/>
          <xsd:element name="exchange" type="xsd:int"/>
          <xsd:element name="number" type="xsd:int"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
    <xsd:schema targetNamespace="urn:listing2"
                xmlns:listing3="urn:listing3"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      
                    <xsd:import namespace="urn:listing3"/>

                
      <xsd:complexType name="Address">
        <xsd:sequence>
          <xsd:element name="streetNum" type="xsd:int"/>
          <xsd:element name="streetName" type="xsd:string"/>
          <xsd:element name="city" type="xsd:string"/>
          <xsd:element name="state" type="xsd:string"/>
          <xsd:element name="phone" type="listing3:Phone"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="GetAddressRequest">
    <wsdl:part name="name" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="GetAddressResponse">
    <wsdl:part name="address" type="tns:Address"/>
  </wsdl:message>
  <wsdl:message name="GetPhoneRequest">
    <wsdl:part name="name" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="GetPhoneResponse">
    <wsdl:part name="phone" type="listing3:Phone"/>
  </wsdl:message>
  <wsdl:portType name="AddressBook">
    <wsdl:operation name="getAddress">
      <wsdl:input message="tns:GetAddressRequest"/>
      <wsdl:output message="tns:GetAddressResponse"/>
    </wsdl:operation>
    <wsdl:operation name="getPhone">
      <wsdl:input message="tns:GetPhoneRequest"/>
      <wsdl:output message="tns:GetPhoneResponse"/>
    </wsdl:operation>
  </wsdl:portType>
</wsdl:definitions>
 

从清单 1 的范例中显而易见导入的主要目的是为了导入命名空间。XSD 导入的一个更常见的用途是导入另一个文件中的命名空间。您可以聚集文件中的命名空间,但是请不要忘记那是您导入的命名空间 ,而不是文件 (不要将 import 语句和 include 语句混淆)。

当您从一个文件导入命名空间时,将看见 XSD 导入语句中的 schemaLocation 属性,但这是一个可选属性。如您在清单 1 中所见, schemaLocation 不是必需的,因为 import 语句的命名空间如 import 语句本身一样,位于同一个位置(在同一个文件中)。实际上,即使您提供了文件位置(如清单 2 所示),XML 解析器也能够忽略该位置(如果 XML 解析器想这样做的话)。 schemaLocation 属性只不过是一个提示(hint)。如果解析器已经知道命名空间中的模式类型,或者有其他寻找这些模式类型的方法,它就不需要定位到你所提供的位置。它的 这个特性也从另一方面提示您 XSD import 语句的主要目的是导入命名空间,而不是告诉您在命名空间的何处可以找到这些声明。当然,大多数时候 XML 解析器并不了解您将要导入的命名空间,所以有必要指定 schemaLocation 属性,并且很容易忘记该属性其实仅仅是一个提示。

现在,查看清单 1 中 用蓝色突出显示的 import 语句。由于使用了 XSD 命名空间,因此应该实际导入该命名空间。但是这是一个十分常见的命名空间。事实上每个 XML 解析器都知道它。大多数解析器允许为其包含 import 语句。其实很多工具甚至允许您忽略红色部分的 import 语句 -- 导入的存在于相同文件中的名字空间。但是导入所有要使用的命名空间是一个好习惯,您应该养成这样的习惯。因为您不知道什么时候或是某个使用您的 WSDL 文件的人可能将使用更严格的工具。

必须确保您在 import 语句中使用的命名空间与您所导入模式的 targetNamespace 相同。在清单 1 的范例中,显然您必须这样做。但是如果您将 urn:listing3 模式移动到一个名为 listing3.xml 的文件中,并导入该文件(如清单 2 所 示),那么这两者的相同可能就不那么明显了。实际上,这可能看起来好像您能够通过使用 import 语句中(而不是 targetNamespace 中)的不同命名空间属性在文件中修改模式的命名空间。这是一个错误。您不能修改命名空间。Import 语句的命名空间属性必须 与该模式的 targetNamespace 一致。

清单23 源于清单 1 。清单 2 是清单 1 将 Phone 模式移到清单 3 中的文件之后的结果。清单 2 中的 import 语句现在包含了 schemaLocation 属性(用蓝色突出显示)。这是从文件导入模式的推荐方法。


清单 2. 导入 Phone 模式 XSD 文件的地址簿 WSDL

<?xml version="1.0" ?>
<wsdl:definitions targetNamespace="urn:listing2"
                  xmlns:tns="urn:listing2"
                  xmlns:listing3="urn:listing3"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <wsdl:types>
    <xsd:schema targetNamespace="urn:listing2"
                xmlns:listing3="urn:listing3"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:import namespace="urn:listing3"  schemaLocation="listing3.xsd"
 />
      <xsd:complexType name="Address">
        <xsd:sequence>
          <xsd:element name="streetNum" type="xsd:int"/>
          <xsd:element name="streetName" type="xsd:string"/>
          <xsd:element name="city" type="xsd:string"/>
          <xsd:element name="state" type="xsd:string"/>
          <xsd:element name="phone" type="listing3:Phone"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="GetAddressRequest">
    <wsdl:part name="name" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="GetAddressResponse">
    <wsdl:part name="address" type="tns:Address"/>
  </wsdl:message>
  <wsdl:message name="GetPhoneRequest">
    <wsdl:part name="name" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="GetPhoneResponse">
    <wsdl:part name="phone" type="listing3:Phone"/>
  </wsdl:message>
  <wsdl:portType name="AddressBook">
    <wsdl:operation name="getAddress">
      <wsdl:input message="tns:GetAddressRequest"/>
      <wsdl:output message="tns:GetAddressResponse"/>
    </wsdl:operation>
    <wsdl:operation name="getPhone">
      <wsdl:input message="tns:GetPhoneRequest"/>
      <wsdl:output message="tns:GetPhoneResponse"/>
    </wsdl:operation>
  </wsdl:portType>
</wsdl:definitions>
 


清单 3. Phone 模式的 XSD 文件

 


<?xml version="1.0" ?>
<xsd:schema targetNamespace="urn:listing3"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:complexType name="Phone">
    <xsd:sequence>
      <xsd:element name="areaCode" type="xsd:int"/>
      <xsd:element name="exchange" type="xsd:int"/>
      <xsd:element name="number" type="xsd:int"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>
 

WSDL 导入

查看清单45 。 它们基本上与清单 2 和 3 相同。清单 4 导入清单 5,这与清单 2 导入清单 3 类似。但是这一次使用 WSDL 导入而不是 XSD 导入。清单 2 与清单 4 之间的差别在清单 4 中用蓝色突出显示。同样,清单 3 与清单 5 之间的差别在清单 5 中用蓝色突出显示。


清单 4. 导入 Phone 模式 WSDL 文件的地址簿 WSDL

<?xml version="1.0" ?>
<wsdl:definitions targetNamespace="urn:listing4"
                  xmlns:tns="urn:listing4"
                  xmlns:listing5="urn:listing5"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
                    <wsdl:import namespace="urn:listing5" location="listing5.wsdl"/>

  <wsdl:types>
    <xsd:schema targetNamespace="urn:listing4"
                xmlns:listing5="urn:listing5"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:import namespace="http://www.w3.org/2001/XMLSchema"/>
      <xsd:complexType name="Address">
        <xsd:sequence>
          <xsd:element name="streetNum" type="xsd:int"/>
          <xsd:element name="streetName" type="xsd:string"/>
          <xsd:element name="city" type="xsd:string"/>
          <xsd:element name="state" type="xsd:string"/>
          <xsd:element name="phone"  type="listing5:Phone"
/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="GetAddressRequest">
    <wsdl:part name="name" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="GetAddressResponse">
    <wsdl:part name="address" type="tns:Address"/>
  </wsdl:message>
  <wsdl:message name="GetPhoneRequest">
    <wsdl:part name="name" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="GetPhoneResponse">
    <wsdl:part name="phone"   type="listing5:Phone"/>
  </wsdl:message>
  <wsdl:portType name="AddressBook">
    <wsdl:operation name="getAddress">
      <wsdl:input message="tns:GetAddressRequest"/>
      <wsdl:output message="tns:GetAddressResponse"/>
    </wsdl:operation>
    <wsdl:operation name="getPhone">
      <wsdl:input message="tns:GetPhoneRequest"/>
      <wsdl:output message="tns:GetPhoneResponse"/>
    </wsdl:operation>
  </wsdl:portType>
</wsdl:definitions>
 

 


清单 5. Phone 模式的 WSDL 文件

<?xml version="1.0" ?>

                    <wsdl:definitions targetNamespace="urn:listing5"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
     
    <xsd:schema targetNamespace="urn:listing5"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:import namespace="http://www.w3.org/2001/XMLSchema"/>
      <xsd:complexType name="Phone">
        <xsd:sequence>
          <xsd:element name="areaCode" type="xsd:int"/>
          <xsd:element name="exchange" type="xsd:int"/>
          <xsd:element name="number" type="xsd:int"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  
    </wsdl:types>
</wsdl:definitions>
 

 

这样做很好吗?如果您在 listing4.wsdl 上运行 WSDL-to-Java 工具,将会发生错误。在清单 4 中,突出显示了两个对 Phone 类型的引用,一个是绿色的,另一个是红色的。绿色的引用在 WSDL 消息语句中。该语句能够查找到 Phone ,因为它是一个 WSDL 语句,并且 WSDL 文件是通过 WSDL import 语句导入 Phone 的。红色的引用在模式中。该引用不能查找到 Phone ,因为它不是通过 XSD import 语句来导入的。您不能在模式之外执行对其他模式的查找。而是必须 从模式内导入其他模式。

如果 Address 类型没有 phone 元素并且因此没有引用 urn:listing5 命名空间,那么清单 4 和 5 将是合法的。然而,对于用 WSDL 导入方法来导入模式信息而言,这不是一个好方法。清单 2 和 3 比清单 4 和 5 更佳。使用 XSD 导入 来导入模式,使用 WSDL 导入来导入 WSDL。

作为 WSDL 导入范例,您会注意到清单 4 中既没有绑定语句,也没有服务语句。估计可能一些其他包含绑定和服务的文件将通过 WSDL import 语句来导入 listing4.wsdl。

关于 WSDL 导入的最后两个注释。与 XSD 导入类似,WSDL 导入的 namespace 属性必须 和所导入 WSDL 的 targetNamespace 相同。WSDL 导入的 location 属性与 XSD 导入的 schemaLocation 属性相似,只不过是一个提示。然而,与 XSD 导入的 schemaLocation 属性不同的是,WSDL 导入的 location 属性是必须给出的。(这在 WSDL 1.1 规范中没有明确提出,但在 WS-I Web 站点的基本概要(Basic Profile)中阐明了这一点。(请参阅参考资料 。) )

 



 

结束语

简单的说,本技巧要说明的是:

  • 使用 XSD 导入来导入模式,使用 WSDL 导入来导入 WSDL,这是一个很好的惯例。
  • 导入所有要使用的命名空间,这是一个好习惯。
  • 导入命名空间的属性值必须与导入的 targetNamespace 值一致。
  • Import 语句的主要目的是导入命名空间。 schemaLocationlocation 属性尽管有时是必需的,但其实只不过是一个提示。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值