 | Level: Intermediate Russell Butek (butek@us.ibm.com), Software Engineer, IBM
09 Jul 2004 This tip explains the nuances of the two types of import statements found in a Web Services Description Language (WSDL) file.
Import statements are easy, right? Just about every programming or interface language has them; and if you're reading this tip, you probably know everything there is to know about imports. So, why should you read a tip about Web Services Description Language (WSDL) file imports? For one thing, two types of import statements exist: XSD imports and WDSL imports. For another, their respective behaviors are not quite identical. Lastly, it's a good idea to know the relationship between the two.
Import vs. include
Before I dive into describing the import statements, let me make the distinction between an import and an include. An import statement brings in other namespaces. An include statement brings other declarations into the current namespace.
XSD import
Let's look at a basic XSD import, such as the one highlighted in red in Listing 1. All that this statement does is import a namespace from one schema to another. The schema, which defines the namespace of urn:listing2, is importing the schema of urn:listing3. That's it. No file is being imported. Both schemas are in this same file in Listing 1.
Listing 1. Address book WSDL using two namespaces
<?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: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>
<xsd:schema targetNamespace="urn:listing2"
xmlns:listing3="urn:listing3"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="urn:listing3"/>
<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="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> |
Hopefully, it's clear from the example in Listing 1 that the primary purpose of an import is to import a namespace. A more common use of the XSD import statement is to import a namespace which appears in another file. You might be gathering the namespace information from the file, but don't forget that it's the namespace that you're importing, not the file (don't confuse an import statement with an include statement).
When you're importing a namespace from a file, you will see a schemaLocation attribute on the XSD import statement, but it is an optional attribute. As you can see in Listing 1, schemaLocation is not necessary because the namespace of the import statement is at the same location (in the same file) as the import statement itself. In fact, even if you had provided a file location (as Listing 2 does), an XML parser is free to ignore the location if it wishes. The schemaLocation attribute is merely a hint. If the parser already knows about the schema types in that namespace, or has some other means of finding them, it does not have to go to the location you gave it. This behavior should be another hint to you that the primary purpose of the XSD import statement is to import the namespace, not tell you where you can find the declarations in that namespace. Of course, most of the time you will be importing namespaces that the XML parser knows nothing about, so the schemaLocation attribute becomes necessary, and it's easy to forget that it's only a hint.
Now, take a look at the import statements I highlighted in blue in Listing 1. Since I use the XSD namespace, I should really import it. But this is a very common namespace. Virtually every XML parser inherently knows about it. Most parsers are rather forgiving about including the import statement for it. In fact, many tools even forgive you if you neglect to include the red import statement -- the imported namespace is in the same file, after all -- but you should really make a habit of importing all namespaces that you use. You never know when you, or someone who uses your WSDL file, might use a stricter tool.
Be very sure that the namespace you use in the import statement is the same as the targetNamespace of the schema you are importing. In the example in Listing 1, it's fairly obvious that you have to do this. But if you move the urn:listing3 schema into a file called listing3.xml, and import that file (as Listing 2 does), then it might not be so obvious. In fact, it might look like you can change the namespace of the schema in the file by using a different namespace attribute on the import statement than in the targetNamespace. This is a mistake. You cannot change namespaces. The namespace attribute of the import statement must match the targetNamespace of the schema.
Listings 2 and 3 are derived from Listing 1. Listing 2 is Listing 1 with the Phone schema removed to a different file -- the file in Listing 3. The import statement in Listing 2 now includes the schemaLocation attribute (highlighted in blue). This is the recommended way to import schema from a file.
Listing 2. Address Book WSDL importing XSD file for Phone schema
<?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: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="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> |
Listing 3. XSD file for Phone schema
<?xml version="1.0" ?>
<xsd:schema targetNamespace="urn:listing3"
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 import
Take a look at Listings 4 and 5. They are essentially the same as Listings 2 and 3. Listing 4 imports Listing 5 as Listing 2 imports Listing 3. But this time, I used a WSDL import rather than an XSD import. The differences between Listing 2 and Listing 4 are highlighted in blue in Listing 4. Likewise, the differences between Listing 3 and Listing 5 are highlighted in blue in Listing 5.
Listing 4. Address Book WSDL importing WSDL file for Phone schema
<?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> |
Listing 5. WSDL file for Phone schema
<?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>
|
Is this a good thing to do? If you run your favorite WSDL-to-Java tool on listing4.wsdl, you should get an error. In Listing 4, I've highlighted two references to the Phone type, one in green and one in red. The green reference is in a WSDL message statement. This statement finds Phone because it is a WSDL statement, and the WSDL file imports Phone via a WSDL import statement. The red reference is in the schema. This reference does not find Phone because it wasn't imported via an XSD import. You cannot step outside of a schema to find other schemas. You must import schemas from inside schemas.
If the Address type did not have a phone element and, therefore, did not reference the urn:listing5 namespace, then this pair, Listings 4 and 5, would be legal. However, it is not a good practice to import schema information with a WSDL import. Listings 2 and 3 are preferred over Listings 4 and 5. Use XSD import to import schema. Use WSDL import to import WSDL.
For an example of proper WSDL imports, you'll notice that Listing 4 doesn't have a binding nor a service statement. Presumably some other file, which contains a binding and a service, will import listing4.wsdl via a WSDL import statement.
A couple of last comments about WSDL imports. Like an XSD import, the namespace attribute of the WSDL import must be the same as the targetNamespace of the imported WSDL. The location attribute of the WSDL import, like the schemaLocation attribute of the XSD import, is just a hint. However, unlike the schemaLocation of the XSD import, the location attribute of the WSDL import is required to be present. (This is not clear in the WSDL 1.1 specification, but the Basic Profile on the WS-I Web site clarifies this. (See Resources.)
Summary
In short, what this tip is trying to say is:
- It is a good practice to use XSD imports to import schema, and to use WSDL imports to import WSDL.
- It is a good practice to import all of the namespaces that you use.
- An attribute value of the import namespace must match the imported targetNamespace value.
- The primary purpose of an import statement is to import namespaces. The
schemaLocation and location attributes, though sometimes necessary, are really only hints.
Resources
- Read the Web Services Description Language (WSDL) 1.1, the specification of WSDL.
- Read the XML Schema Primer.
- Browse the Web Services Interoperability (WS-I) organization's web pages.
- Get the IBM® WebSphere® Application Server Technology for Developers, Version 6.0, an early release of the next WebSphere Application Server.
- Find additional SOA and Web services technology resources on the developerWorks SOA and Web services technology zone.
- Find a number of Web services programming tips from developerWorks.
- Browse for books on these and other technical topics.
- Interested in test driving IBM products without the typical high-cost entry point or short-term evaluation license? The developerWorks Subscription provides a low-cost, 12-month, single-user license for WebSphere, DB2®, Lotus®, Rational®, and Tivoli® products -- including the Eclipse-based WebSphere Studio IDE -- to develop, test, evaluate, and demonstrate your applications.
About the author  | |  | Russell Butek is an IBM Web services consultant. He has been one of the developers of the IBM WebSphere Web services engine. He is also a member the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC 1.0. Previously, he was a developer of the IBM CORBA ORB and an IBM representative on a number of OMG task forces, including chairing the portable interceptor task force. Contact Russell at butek@us.ibm.com. |
Rate this page
|  |