XML namespaces play an important role in SOAP messages. A SOAP message may include several different XML elements in the Header and Body elements, and to avoid name collisions each of these elements should be identified by a unique namespace. For example, a SOAP message that contains the purchaseOrder element as well as message-id and XML digital-signature header blocks would include no fewer than six different namespaces, as shown in bold in Listing 4-5.
Listing 4-5 Using XML Namespaces in a SOAP Message
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sec="http://schemas.xmlsoap.org/soap/security/2000-12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id"> <soap:Header> <mi:message-id>11d1def534ea:b1c5fa:f3bfb4dcd7:-8000</mi:message-id> <sec:Signature> ... </sec:Signature> </soap:Header> <soap:Body sec:id="Body"> <po:purchaseOrder orderDate="2003-09-22" xmlns:po="http://www.Monson-Haefel.com/jwsbook/PO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> ... </po:purchaseOrder> </soap:Body> </soap:Envelope>
The use of XML namespaces is what makes SOAP such a flexible and extensible protocol. An XML namespace fully qualifies an element or attribute name, as you learned in Section 2.2. Because their use was discussed in detail there, the basic mechanics of XML namespaces aren't covered here.
Of the six namespaces declared in Listing 4-5, the first, declared in the Envelope element, defines the namespace of the standard SOAP elements—Envelope, Header, and Body—as shown in bold in the following snippet from Listing 4-5.
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sec="http://schemas.xmlsoap.org/soap/security/2000-12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id"> ... </soap:Envelope>
This namespace determines the version of SOAP used (1.1 at this point). SOAP messages must declare the namespace of the Envelope element to be the standard SOAP 1.1 envelope namespace, "http://schemas.xmlsoap.org/soap/envelope/". If a SOAP application receives a message based on some other namespace, it must generate a fault. This rule ensures that all conforming messages are using exactly the same namespace and XML schema, and therefore the same processing rules.BP
The second, third, and fourth namespaces declared in the Envelope element are associated with XML elements in the header blocks:
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sec="http://schemas.xmlsoap.org/soap/security/2000-12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id"> <soap:Header> <mi:message-id>11d1def534ea:b1c5fa:f3bfb4dcd7:-8000</mi:message-id> <sec:Signature> <ds:Signature> ... </ds:Signature> </sec:Signature> </soap:Header> <soap:Body> <!-- Application-specific data goes here --> </soap:Body> </soap:Envelope>
Each header block in the Header element should have its own namespace. This is particularly important because namespaces help SOAP applications identify header blocks and process them separately. A variety of “standard” header blocks that address topics such as security, transactions, and other qualities of service are in development by several organizations, including W3C, OASIS, IETF, Microsoft, BEA, and IBM. All of the proposed standards define their own namespaces and XML schemas, as well as processing requirements—but none of these “standard” header blocks is addressed by J2EE 1.4 Web Services yet.
In Listing 4-5, two other namespaces are declared in the immediate child of the Body element, as shown in the following snippet. The first namespace declaration belongs to the Purchase Order Markup Language defined by Monson-Haefel Books (see Part I: XML).
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sec="http://schemas.xmlsoap.org/soap/security/2000-12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id" > <soap:Header> <!-- Header blocks go here --> </soap:Header> <soap:Body sec:id="Body"> <po:purchaseOrder orderDate="2003-09-22" xmlns:po="http://www.Monson-Haefel.com/jwsbook/PO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> ... </po:purchaseOrder> </soap:Body> </soap:Envelope>
All of the local elements of a SOAP message must be namespace-qualified (prefixed with the SOAP 1.1 namespace), because the XML schema for SOAP 1.1 specifies the elementFormDefault attribute as "qualified". In addition, the Basic Profile 1.0 requires that all the application-specific elements contained by the Body element must be qualified.BP Unqualified elements in a SOAP Body element create too much ambiguity as to the meaning and proper structure of elements. (See Section 3.1.6 for details about qualified and unqualified local elements.)
The xsi:schemaLocation attribute (the attribute that provides the URL of the schema) may be declared for validation, but in most cases the SOAP stack will have handled this matter at design time, so that explicit declaration of the xsi :schemaLocation in a SOAP message is not necessary.
A SOAP stack is a library of code designed to process and transmit SOAP messages. For example, Apache Axis, J2EE 1.4, Perl::Lite, and Microsoft .NET all have their own SOAP stacks, their own libraries of code for processing SOAP messages.
Some SOAP stacks make extensive use of the XML schema-instance namespace to indicate the data types of elements (for example, xsi:type = "xsd:float"). Other SOAP stacks do not, though, which causes problems when the receiver expects elements to be typed but the sender doesn't type them. According to the BP, the xsi:type attribute must be used only to indicate that a derived XML type is being used in place of its base type—for example, a USAddress in place of an Address.BP
As you learned in Section 2.2, the real power of XML namespaces goes beyond simply avoiding name collisions, to proper versioning and processing. Using fully qualified names for the SOAP and application-specific data tells the SOAP receiver how to process the message, and which XML schemas to apply in order to validate its contents. Differences in a particular version of a header block, for example, can affect how a receiver processes messages, so identifying the header-block version by its namespace enables a receiver to switch processing models, or to reject messages if it doesn't support the specified version. Similarly, properly identifying the types of XML elements contained in the Body element enables a SOAP receiver either to process those elements using the appropriate code modules or possibly to reject the message if it doesn't support the specified namespace.
The term “code module” is used to express an aspect of computer code that performs some function. A code module may be a separate code library, a service, or simply a branch of logic within a larger set of code.
For example, if a new algorithm is used to generate the message-id header block, then the namespace of the message-id header could change to reflect the use of the new algorithm. The SOAP message in Listing 4-6 contains a message-id header block with a new namespace, which indicates that it's different from the message-id header block used in previous examples.
Listing 4-6 Changing the Namespace of a Header Block
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sec="http://schemas.xmlsoap.org/soap/security/2000-12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mi2="http://www.Monson-Haefel.com/jwsbook/message-id_version2/"> <soap:Header> <mi2:message-id>1-203950-3485-30503453098</mi2:message-id> <sec:Signature> ... </sec:Signature> </soap:Header> <soap:Body> <!-- Application-specific data goes here --> <soap:Body> </soap:Envelope>
Namespaces enable a SOAP receiver to handle different versions of a SOAP message, without impairing backward compatibility or requiring different Web service endpoints for each version of a particular SOAP message.
As you can see from the previous examples, a SOAP message may contain many different namespaces, which makes SOAP messaging very modular. This modularity enables different parts of a SOAP message to be processed independently of other parts and to evolve separately. The version of the SOAP Envelope or header blocks may change over time, while the structure of the application-specific contents in the Body element remains the same. Similarly, the application-specific contents may change while the version of the SOAP message and the header blocks do not.
The modularity of SOAP messaging permits the code that processes the SOAP messages to be modular as well. The code that processes the element Envelope is independent of the code that processes the header blocks, which is independent of the code that processes application-specific data in the SOAP Body element. Modularity enables you to use different code libraries to process different parts of a SOAP message. Figure 4-4 shows the structure of a SOAP message and the code modules used to process each of its parts. The code modules in gray boxes are associated with namespaces used in this SOAP message. The code modules in white boxes represent alternatives; they are associated with different namespaces, used to process alternative versions of the SOAP message.
Figure 4-4. Using the Appropriate Code Modules with SOAP Namespaces
In all the examples so far, the namespaces of the header blocks have been declared in the Envelope element. Doing so is not required; we could just as easily declare those namespaces in the Header element or the header blocks. As you learned in Section 2.2, namespaces are always locally scoped and can be declared at any level as long as the elements in question are within that scope (the element the namespace is declared in, and its subelements). For example, we could declare the header-block namespaces in the Header element, as shown in the boldface code lines in Listing 4-7.
Listing 4-7 Declaring XML Namespaces in a Header Element
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" > <soap:Header xmlns:sec="http://schemas.xmlsoap.org/soap/security/2000-12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id" > <mi:message-id>11d1def534:b1c5fa:f3bfb4dcd7:-8000</mi:message-id> <sec:Signature> ... </sec:Signature> </soap:Header> <soap:Body> <!-- Application-specific data goes here --> </soap:Body> </soap:Envelope>
We could also declare each namespace in its own header block as in Listing 4-8.
Listing 4-8 Declaring XML Namespaces in Header Blocks
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" > <soap:Header> <mi:message-id xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id" > 11d1def534ea:b1c5fa:f3bfb4dcd7:-8000 </mi:message-id> <sec:Signature xmlns:sec="http://schemas.xmlsoap.org/soap/security/2000-12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> ... </sec:Signature> </soap:Header> <soap:Body> <!-- Application-specific data goes here --> </soap:Body> </soap:Envelope>
Although application-specific elements in the Body element must be qualified by prefixes, there is no such requirement for the elements contained within a Header element. Local elements of header blocks may be qualified or unqualified.
The way to declare namespaces is really a matter of style. As long as you adhere to the conventions and limitations of namespace declarations as they're described in the W3C Namespaces in XML recommendation,3 you can use any style you wish. Table 4-1 shows the namespace prefixes used in this book and in the WS-I Basic Profile 1.0.
Table 4-1. Namespace Prefixes
Prefix |
Namespace |
---|---|
soap |
"http://schemas.xmlsoap.org/soap/envelope/" |
xsi |
"http://www.w3.org/2001/XMLSchema-instance" |
xsd |
"http://www.w3.org/2001/XMLSchema" |
soapenc |
"http://schemas.xmlsoap.org/soap/encoding/" |
wsdl |
"http://schemas.xmlsoap.org/wsdl/" |
soapbind |
"http://schemas.xmlsoap.org/wsdl/soap/" |
wsi |
"http://ws-i.org/schemas/conformanceClaim/" |