In a typical Web services scenario, you normally let the tooling handle all the nuances of namespaces for you. But sometimes you have to deal with namespace issues yourself, particularly if you are constructing a SOAP message for a particular Web service using the SOAP with Attachments API for Java (SAAJ). This tip is meant for those of you who have to construct messages -- or parts of messages -- without the tooling's help.
While namespaces might seem complicated, all you really have to know is a short list of rules:
- If the WSDL style is RPC, then you look to the WSDL binding's
wsdlsoap:bodyelement for the namespace. - If
wsdlsoap:bodyhas a namespace attribute (and the Web Services Interoperability Orginzation's (WS-I) Basic Profile (see Resources) requires it for RPC-style), then that is the namespace of the operation element in the SOAP message. - If
wsdlsoap:bodyhas no namespace, then the operation element is unqualified. - For data elements:
- If the element is defined by a root element (not a root type), then its namespace is the namespace of that root element;
- If the element is not defined by a root, the element is unqualified (for a caveat to this rule, see the discussion of elementFormDefault below).
These are simple rules, but like most rules, they need a little explanation. The rest of this tip shows you various examples of these rules in action.
There are two typical types of Web Services Description Language (WSDL) files: RPC/literal and document/literal wrapped. There are others, but in this tip, I cover only those two. (For details of the various types of WSDL, see the paper "Which style of WSDL should I use?" -- see Resources.)
Listing 1 contains an RPC/literal WSDL which has three operations: op1, op2, and op3. Notice the various namespaces in the WSDL file, highlighted in bold.
Listing 1. RPC/literal WSDL
<?xml version="1.0" encoding="UTF-8"?>
<definitions
targetNamespace="http://apiNamespace.com"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://apiNamespace.com"
xmlns:data="http://dataNamespace.com"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<types>
<schema
targetNamespace="http://refNamespace.com"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://refNamespace.com">
<element name="RefDataElem" type="int"/>
</schema>
<schema
targetNamespace="http://dataNamespace.com"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ref="http://refNamespace.com"
xmlns:tns="http://dataNamespace.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<import namespace="http://refNamespace.com"/>
<complexType name="Data">
<sequence>
<element name="data1" type="int"/>
<element name="data2" type="int"/>
</sequence>
</complexType>
<element name="DataElem" nillable=
"true" type="tns:Data"/>
<complexType name="Data2">
<sequence>
<element ref="ref:RefDataElem"/>
</sequence>
</complexType>
</schema>
</types>
<message name="op1Request">
<part name="in" type="data:Data"/>
</message>
<message name="op1Response">
<part name="op1Return" type="data:Data"/>
</message>
<message name="op2Request">
<part name="in" type="data:Data"/>
</message>
<message name="op2Response">
<part name="op2Return" type="data:Data"/>
</message>
<message name="op3Request">
<part name="in1" element="data:DataElem"/>
<part name="in2" type="data:Data2"/>
</message>
<message name="op3Response">
<part name="op3Return" type="data:Data2"/>
</message>
<portType name="Sample">
<operation name="op1">
<input message="tns:op1Request"/>
<output message="tns:op1Response"/>
</operation>
<operation name="op2">
<input message="tns:op2Request"/>
<output message="tns:op2Response"/>
</operation>
<operation name="op3">
<input message="tns:op3Request"/>
<output message="tns:op3Response"/>
</operation>
</portType>
<binding name="SampleSoapBinding" type="tns:Sample">
<wsdlsoap:binding style="rpc" transport=
"http://schemas.xmlsoap.org/soap/http"/>
<operation name="op1">
<wsdlsoap:operation soapAction=""/>
<input>
<wsdlsoap:body namespace=
"http://apiNamespace.com" use="literal"/>
</input>
<output>
<wsdlsoap:body namespace=
"http://apiNamespace.com" use="literal"/>
</output>
</operation>
<operation name="op2">
<wsdlsoap:operation soapAction=""/>
<input>
<wsdlsoap:body namespace=
"http://op2Namespace.com" use="literal"/>
</input>
<output>
<wsdlsoap:body namespace=
"http://op2Namespace.com" use="literal"/>
</output>
</operation>
<operation name="op3">
<wsdlsoap:operation soapAction=""/>
<input>
<wsdlsoap:body use="literal"/>
</input>
<output>
<wsdlsoap:body use="literal"/>
</output>
</operation>
</binding>
<service name="SampleService">
<port binding="tns:SampleSoapBinding" name=
"Sample">
<wsdlsoap:address location=
"http://localhost:9080/RPCNamespaces/services/Sample"/>
</port>
</service>
</definitions> |
Take a look at the namespaces in the binding's wsdlsoap:body elements for each operation. op1 and op2 are examples of rule 1.1 (see below for the SOAP messages). op3 is an example of rule 1.2. op1 shows the conventional example of using the targetNamespace -- in this case "http://apiNamespace.com" -- as the operation's namespace, but this is merely a convention. op2 uses a namespace not used anywhere else in the WSDL. And op3 defines no namespace at all.
Listings 2, 3, and 4 show the SOAP messages for calls to op1, op2, and op3, respectively. Note the namespaces within the messages, highlighted in bold.
Listing 2. RPC/literal request/response SOAP messages for op1
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p582:op1 xmlns:p582="http://apiNamespace.com">
<in>
<data1>1</data1>
<data2>2</data2>
</in>
</p582:op1>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p582:op1Response xmlns:p582="http://apiNamespace.com">
<op1Return>
<data1>10</data1>
<data2>20</data2>
</op1Return>
</p582:op1Response>
</soapenv:Body>
</soapenv:Envelope> |
As mentioned, the SOAP messages in Listing 2 follow rule 1.1. op1 has the namespace "http://apiNamespace.com." These messages also follow rule 2.2. None of the parameter data is defined using a root element, only a root type -- data -- and its child elements. Since no root element is used, the elements are all unqualified.
Listing 3. RPC/literal request/response SOAP messages for op2
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p999:op2 xmlns:p999="http://op2Namespace.com">
<in>
<data1>3</data1>
<data2>4</data2>
</in>
</p999:op2>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p999:op2Response xmlns:p999="http://op2Namespace.com">
<op2Return>
<data1>300</data1>
<data2>400</data2>
</op2Return>
</p999:op2Response>
</soapenv:Body>
</soapenv:Envelope> |
The only real difference between op1's and op2's messages (Listing 2 versus Listing 3) is that op2's messages show that you can use any namespace you choose; you do not have to use the WSDL definition's targetNamespace.
Listing 4. RPC/literal request/response SOAP messages for op3
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<op3>
<p10:DataElem xmlns:p10=
"http://dataNamespace.com">
<data1>5</data1>
<data2>6</data2>
</p10:DataElem>
<in2>
<p971:RefDataElem xmlns:p971=
"http://refNamespace.com">7</p971:RefDataElem>
</in2>
</op3>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<op3Response>
<op3Return>
<p971:RefDataElem xmlns:p971="http://refNamespace.com">7</p971:RefDataElem>
</op3Return>
</op3Response>
</soapenv:Body>
</soapenv:Envelope> |
op3 is quite different from the other operations. First, there was no namespace defined, so the <op3> and <op3Response> tags are unqualified. This follows rule 1.2. (Note: Remember that op3 is not WS-I compliant -- see WS-I compliance sidebar.)
Secondly, the part named in1 refers to a root element, not a root type. Since it is an element part, the part name, in1, is ignored in favor of the element name, DataElem. And since you're using the element name, you must also use the element's namespace, "http://dataNamespace.com." This follows rule 2.1.
Lastly, rule 2.1 is again invoked for the type element for in2, which is a reference to a root element: RefDataElem. This element is defined in yet another namespace: "http://refNamespace.com."
The WSDL in Listing 5 is the equivalent to the WSDL in Listing 1. It is document/literal wrapped instead of RPC/literal. The Java APIs generated for this WSDL are identical to the Java APIs generated for the RPC/literal WSDL, but the SOAP messages are potentially somewhat different. Once again, the namespaces are highlighted in bold.
Listing 5. document/literal wrapped WSDL
<?xml version="1.0" encoding="UTF-8"?>
<definitions
targetNamespace="http://apiNamespace.com"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://apiNamespace.com"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<types>
<schema
targetNamespace="http://refNamespace.com"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://refNamespace.com">
<element name="RefDataElem" type="int"/>
</schema>
<schema
targetNamespace="http://dataNamespace.com"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ref="http://refNamespace.com"
xmlns:tns="http://dataNamespace.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<import namespace="http://refNamespace.com"/>
<complexType name="Data">
<sequence>
<element name="data1" type="int"/>
<element name="data2" type="int"/>
</sequence>
</complexType>
<element name="DataElem" nillable="true" type="tns:Data"/>
<complexType name="Data2">
<sequence>
<element ref="ref:RefDataElem"/>
</sequence>
</complexType>
</schema>
<schema
targetNamespace="http://apiNamespace.com"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:data="http://dataNamespace.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<import namespace="http://dataNamespace.com"/>
<element name="op1">
<complexType>
<sequence>
<element name="in" type="data:Data"/>
</sequence>
</complexType>
</element>
<element name="op1Response">
<complexType>
<sequence>
<element name="op1Return" type="data:Data"/>
</sequence>
</complexType>
</element>
<element name="op2">
<complexType>
<sequence>
<element name="in" type="data:Data"/>
</sequence>
</complexType>
</element>
<element name="op2Response">
<complexType>
<sequence>
<element name="op2Return" type="data:Data"/>
</sequence>
</complexType>
</element>
<element name="op3">
<complexType>
<sequence>
<element ref="data:DataElem"/>
<element name="in2" type="data:Data2"/>
</sequence>
</complexType>
</element>
<element name="op3Response">
<complexType>
<sequence>
<element name="op3Return" type="data:Data2"/>
</sequence>
</complexType>
</element>
</schema>
</types>
<message name="op1Request">
<part element="tns:op1" name="parameters"/>
</message>
<message name="op1Response">
<part element="tns:op1Response" name="parameters"/>
</message>
<message name="op2Request">
<part element="tns:op2" name="parameters"/>
</message>
<message name="op2Response">
<part element="tns:op2Response" name="parameters"/>
</message>
<message name="op3Request">
<part element="tns:op3" name="parameters"/>
</message>
<message name="op3Response">
<part element="tns:op3Response" name="parameters"/>
</message>
<portType name="Sample">
<operation name="op1">
<input message="tns:op1Request"/>
<output message="tns:op1Response"/>
</operation>
<operation name="op2">
<input message="tns:op2Request"/>
<output message="tns:op2Response"/>
</operation>
<operation name="op3">
<input message="tns:op3Request"/>
<output message="tns:op3Response"/>
</operation>
</portType>
<binding name="SampleSoapBinding" type="tns:Sample">
<wsdlsoap:binding style="document" transport=
"http://schemas.xmlsoap.org/soap/http"/>
<operation name="op1">
<wsdlsoap:operation soapAction=""/>
<input>
<wsdlsoap:body namespace=
"http://apiNamespace.com" use="literal"/>
</input>
<output>
<wsdlsoap:body namespace=
"http://apiNamespace.com" use="literal"/>
</output>
</operation>
<operation name="op2">
<wsdlsoap:operation soapAction=""/>
<input>
<wsdlsoap:body namespace=
"http://op2Namespace.com" use="literal"/>
</input>
<output>
<wsdlsoap:body namespace=
"http://op2Namespace.com" use="literal"/>
</output>
</operation>
<operation name="op3">
<wsdlsoap:operation soapAction=""/>
<input>
<wsdlsoap:body use="literal"/>
</input>
<output>
<wsdlsoap:body use="literal"/>
</output>
</operation>
</binding>
<service name="SampleService">
<port binding="tns:SampleSoapBinding" name="Sample">
<wsdlsoap:address location=
"http://localhost:9080/Wrapped/services/Sample"/>
</port>
</service>
</definitions> |
For op1, the SOAP messages for the document/literal wrapped service are identical to the SOAP messages for the RPC/literal service (see Listing 2). This is the most common sort of document/literal wrapped operation. Be aware that you're now following rule 2.1, not rule 1.1; you're getting the namespace from an element, not from a wsdl:soapbody. Notice the convention in the WSDL that the wrapper elements are defined in the same namespace as the WSDL itself: "http://apiNamespace.com." They could have been defined in any namespace, but by following this convention, the wrapped messages are identical to the RPC/literal messages.
op2's document/literal wrapped SOAP messages are in Listing 6.
Listing 6. Document/literal wrapped request/response SOAP messages for op2
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p582:op2 xmlns:p582="http://apiNamespace.com">
<in>
<data1>3</data1>
<data2>4</data2>
</in>
</q0:op2>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p582:op2Response xmlns:p582="http://apiNamespace.com">
<op2Return>
<data1>300</data1>
<data2>400</data2>
</op2Return>
</p582:op2Response>
</soapenv:Body>
</soapenv:Envelope> |
The document/literal wrapped messages for op2 make it much more obvious that you're following rule 2.1 rather than rule 1.1. You're completely ignoring the namespace in the binding's wsdl:soapbody.
Finally, let's compare the SOAP messages for the RPC/literal op3 (Listing 4) and the document/literal wrapped op3 (Listing 7). Like op2, the only difference is the namespace of op3. The RPC version has no namespace, but the document version does have a namespace; just like all the other document messages, it gets the namespace from the element's namespace: rule 2.1.
Listing 7. Document/literal wrapped request/response SOAP messages for op3
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p582:op3 xmlns:p582="http://apiNamespace.com">
<p10:DataElem xmlns:p10="http://dataNamespace.com">
<data1>5</data1>
<data2>6</data2>
</p10:DataElem>
<in2>
<p971:RefDataElem xmlns:p971=
"http://refNamespace.com">7</p971:RefDataElem>
</in2>
</p582:op3>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p582:op3Response xmlns:p582="http://apiNamespace.com">
<op3Return>
<p971:RefDataElem xmlns:p971=
"http://refNamespace.com">7</p971:RefDataElem>
</op3Return>
</p582:op3Response>
</soapenv:Body>
</soapenv:Envelope> |
A comment about the default namespace
The default namespace is the one that you use to eliminate the need for a prefix. For example, in Listing 8, both e and f are in the default namespace, which is defined here as urn:default; e is in it because the default namespace is defined on e, and f is in it because it's a child of e.
Listing 8. Example of default namespace use
<e xmlns="urn:default"> <f/> </e> |
Here's some advice: don't use the default namespace in instance data.
- If you use the default namespace and you take something out of context -- for example,
<f/>-- then you have no idea just by looking at it whether that element is unqualified or whether it is qualified by some ancestor. - If you really want a child to be unqualified, then you must introduce the blank namespace to do it. For instance, in Listing 9, e is in the
urn:defaultnamespace and f is unqualified in a rather strange-looking manner.
Listing 9. Example of an unqualified name inside a default namespace
<e xmlns="urn:default"> <f xmlns=""/> </e> |
elementFormDefault="qualified"
A schema attribute that has an affect on namespaces is elementFormDefault. The default setting for this attribute is "unqualified," which is what you've been seeing so far -- child elements are unqualified. But if you add elementFormDefault="qualified" to all of the schemas in the document/literal wrapped WSDL, then all elements in the messages would be qualified with their parent's namespace. For example, Listing 10 contains the document/literal wrapped messages for the op3 operation from the WSDL in Listing 5 when elementFormDefault is qualified. In general, you do not want to use elementFormDefault="qualified" because it bloats the messages, but a year or more ago there were interoperability issues between various vendors, and setting this attribute sometimes fixed the problems.
Listing 10. Document/literal wrapped request/response SOAP messages for op1 with elementFormDefault="qualified"
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p582:op1 xmlns:p582="http://apiNamespace.com">
<p582:in>
<p10:data1 xmlns:p10=
"http://dataNamespace.com">1</p10:data1>
<p10:data2 xmlns:p10=
"http://dataNamespace.com">2</p10:data2>
</p582:in>
</p582:op1>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<p582:op1Response xmlns:p582="http://apiNamespace.com">
<p582:op1Return>
<p10:data1 xmlns:p10=
"http://dataNamespace.com">10</p10:data1>
<p10:data2 xmlns:p10=
"http://dataNamespace.com">20</p10:data2>
</p582:op1Return>
</p582:op1Response>
</soapenv:Body>
</soapenv:Envelope> |
Under normal circumstances, you should never worry about namespaces in the SOAP message. But there are times when you must; for example, when you have to create your SOAP message by hand. In this case, you must have a thorough understanding of how WSDL maps to SOAP. If you follow the rules presented in this tip, you should have no problem hand-writing your SOAP messages with all the proper namespaces.
- Read W3C's SOAP with Attachments specification.
- Understand what document/literal wrapped is by reading the article "Which style of WSDL should I use?" (developerWorks, October 2003).
- Read the Web Services Description Language (WSDL) 1.1, the specification of WSDL.
- Learn more about IBM and WS-I.
- Read the XML Schema Primer.
- Browse the Web Services Interoperability (WS-I) organization's Web pages.
- Java API for XML-Based RPC (JAX-RPC) Downloads & Specifications provides links to the JAX-RPC 1.1 specification.
- Browse for books on these and other technical topics.
- Get involved in the developerWorks community by participating in
developerWorks blogs.
- The IBM developerWorks team hosts hundreds of technical briefings around the world which you can attend at no charge.
- Want more? The developerWorks SOA and Web services zone hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services applications.
Russell Butek is an IBM Web services consultant. He was one of the developers of the IBM WebSphere Web services engine. He was 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.


