SOAP and PHP 5

Exclusive offer: get 50% off this eBook here
PHP Web 2.0 Mashup Projects: Practical PHP Mashups with Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo!

PHP Web 2.0 Mashup Projects: Practical PHP Mashups with Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo! — Save 50%

Create practical mashups in PHP grabbing and mixing data from Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo!, Last.fm, and 411Sync.com

£14.99    £7.50
by Shu-Wai Chow | October 2007 | AJAX MySQL Open Source PHP Web Development

Creating your own search engine in the past would require a massive amount of hardware resources, and complex search and spidering algorithms. Lucky for us, search engines like Google, Microsoft MSN, and Yahoo! have already done this for us. Even luckier for us, these sites have released web services for us to query their data centers and retrieve results. Our main advantage is that all three offer web APIs, so we can leverage the data of all three engines. Instead of just one set of results from one search engine, our application will query each engine and present the results to the user on one page. No longer will users have to visit these sites individually to search each engine.

In this article, we will cover one of the important elements for building a search engine, SOAP, and we will see how PHP 5 interacts with it.

SOAP

SOAP, formerly known as Simple Object Access Protocol (until the acronym was dropped in version 1.2), came around shortly after XML-RPC was released. It was created by a group of developers with backing from Microsoft. Interestingly, the creator of XML-RPC, David Winer, was also one of the primary contributors to SOAP. Winer released XML-RPC before SOAP, when it became apparent to him that though SOAP was still a way away from being completed, there was an immediate need for some sort of web service protocol.

Like XML-RPC, SOAP is an XML-based web service protocol. SOAP, however, satisfies a lot of the shortcomings of XML-RPC: namely the lack of user-defined data types, better character set support, and rudimentary security. It is quite simply, a more powerful and flexible protocol than REST or XML-RPC. Unfortunately, sacrifices come with that power. SOAP is a much more complex and rigid protocol. For example, even though SOAP can stand alone, it is much more useful when you use another XML-based standard, called Web Services Descriptor Language (WSDL), in conjunction with it. Therefore, in order to be proficient with SOAP, you should also be proficient with WSDL.

The most-levied criticism of SOAP is that it is overly complex. Indeed, SOAP is not simple. It is long and verbose. You need to know how namespaces work in XML. SOAP can rely heavily on other standards. This is true for most implementations of SOAP, including Microsoft Live Search, which we will be looking at. The most common external specifications used by a SOAP-based service is WSDL to describe its available services, and that, in turn, usually relies on XML Schema Data (XSD) to describe its data types. In order to "know" SOAP, it would be extremely useful to have some knowledge of WSDL and XSD. This will allow one to figure out how to use the majority of SOAP services.

We are going to take a "need to know" approach when looking at SOAP. Microsoft Live Search's SOAP API uses WSDL and XSD, so we will take a look at SOAP with the other two in mind. We will limit our discussion on how to gather information about the web service that you, as a web service consumer, would need and how to write SOAP requests using PHP 5 against it. Even though this article will just introduce you to the core necessities of SOAP, there is a lot of information and detail.

SOAP is very meticulous and you have to keep track of a fair amount of things. Do not be discouraged, take notes if you have to, and be patient.

All three, SOAP, WSD, and XSD are maintained by the W3C. All three specifications are available for your perusal. The official SOAP specification is located at http://www.w3.org/TR/soap/. WSDL specification is located at http://www.w3.org/TR/wsdl. Finally, the recommended XSD specification can be found at http://www.w3.org/XML/Schema.

Web Services Descriptor Language (WSDL) With XML Schema Data (XSD)

Out of all the drawbacks of XML-RPC and REST, there is one that is prominent. Both of these protocols rely heavily on good documentation by the service provider in order to use them. Lacking this, you really do not know what operations are available to you, what parameters you need to pass in order to use them, and what you should expect to get back. Even worse, an XML-RPC or REST service may be poorly or inaccurately documented and give you inaccurate or unexpected results. SOAP addresses this by relying on another XML standard called WSDL to set the rules on which web service methods are available, how parameters should be passed, and what data type might be returned. A service's WSDL document, basically, is an XML version of the documentation. If a SOAP-based service is bound to a WSDL document, and most of them are, requests and responses must adhere to the rules set in the WSDL document, otherwise a fault will occur.

WSDL is an acronym for a technical language. When referring to a specific web service's WSDL document, people commonly refer to the document as "the WSDL" even though that is grammatically incorrect.

Being XML-based, this allows clients to automatically discover everything about the functionality of the web service. Human-readable documentation is technically not required for a SOAP service that uses a WSDL document, though it is still highly recommended. Let's take a look at the structure of a WSDL document and how we can use it to figure out what is available to us in a SOAP-based web service. Out of all three specifications that we're going to look at in relationship to SOAP, WSDL is the most ethereal. Both supporters and detractors often call writing WSDL documents a black art. As we go through this, I will stress the main points and just briefly note other uses or exceptions.

Basic WSDL Structure

Beginning with a root definitions element, WSDL documents follow this basic structure:

    <definitions>
        <types>
        …
        </types>
        <message>
        …
        </message>
        <portType>
        …
        </portType>
        <binding>
        …
        </binding>
    </definitions>

As you can see, in addition to the definitions element, there are four main sections to a WSDL document: types, message, portType, and binding. Let's take a look at these in further detail.

Google used to provide a SOAP service for their web search engine. However, this service is now deprecated, and no new developer API keys are given out. This is unfortunate because the service was simple enough to learn SOAP quickly, but complex enough to get a thorough exposure to SOAP. Luckily, the service itself is still working and the WSDL is still available. As we go through WSDL elements, we will look at the Google SOAP Search WSDL and Microsoft Live Search API WSDL documents for examples. These are available at http://api.google.com/GoogleSearch.wsdl and http://soap.search.msn.com/webservices.asmx?wsdl respectively.

definitions Element

This is the root element of a WSDL document. If the WSDL relies on other specifications, their namespace declarations would be made here. Let's take a look at Google's WSDL's definition tag:

    <definitions name="GoogleSearch"
        targetNamespace="urn:GoogleSearch"
        xmlns:typens="urn:GoogleSearch"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
        xmlns="http://schemas.xmlsoap.org/wsdl/">

The more common ones you'll run across are xsd for schema namespace, wsdl for the WSDL framework itself, and soap and soapenc for SOAP bindings. As these namespaces refer to W3C standards, you will run across them regardless of the web service implementation. Note that some searches use an equally common prefix, xs, for XML Schema. tns is another common namespace. It means "this namespace" and is a convention used to refer to the WSDL itself.

types Element

In a WSDL document, data types used by requests and responses need to be explicitly declared and defined. The textbook answer that you'll find is that the types element is where this is done. In theory, this is true. In practice, this is mostly true. The types element is used only for special data types.

To achieve platform neutrality, WSDL defaults to, and most implementations use, XSD to describe its data types. In XSD, many basic data types are already included and do not need to be declared.

Common Built-in XSD Data Types

Time

Date

Boolean

String

Base64Binary

Float

Double

Integer

Byte

For a complete list, see the recommendation on XSD data types at http://www.w3.org/TR/xmlschema-2/.

If the web service utilizes nothing more than these built-in data types, there is no need to have special data types, and thus, types will be empty. So, the data types will just be referred to later, when we define the parameters.

There are three occasions where data types would be defined here:

  1. If you want a special data type that is based on a built-in data type. Most commonly this is a built-in, whose value is restricted in some way. These are known as simple types.
  2. If the data type is an object, it is known as a complex type in XSD, and must be declared.
  3. An array, which can be described as a hybrid of the former two.

Let's take a look at some examples of what we will encounter in the types element.

Simple Type

Sometimes, you need to restrict or refine a value of a built-in data type. For example, in a hospital's patient database, it would be ludicrous to have the length of a field called Age to be more than three digits. To add such a restriction in the SOAP world, you would have to define Age here in the types section as a new type.

Simple types must be based on an existing built-in type. They cannot have children or properties like complex types. Generally, a simple type is defined with the simpleType element, the name as an attribute, followed by the restriction or definition. If the simple type is a restriction, the built-in data type that it is based on, is defined in the base attribute of the restriction element.

For example, a restriction for an age can look like this:

    <xsd:simpleType name="Age">
        <xsd:restriction base="xsd:integer">
            <xsd:totalDigits value="3" />
        </xsd:restriction>
    </xsd:simpleType>

Children elements of restriction define what is acceptable for the value. totalDigits is used to restrict a value based on the character length. A table of common restrictions follows:

Restriction

Use

Applicable In

enumeration

Specifies a list of acceptable values.

All except boolean

fractionDigits

Defines the number of decimal places allowed.

Integers

length

Defines the exact number of characters allowed.

Strings and all binaries

maxExclusive/ maxInclusive

Defines the maximum value allowed. If Exclusive is used, value cannot be equal to the definition. If Inclusive, can be equal to, but not greater than, this definition.

All numeric and dates

minLength/ maxLength

Defines the minimum and maximum number of characters or list items allowed.

Strings and all binaries

minExclusive/ minInclusive

Defines the minimum value allowed. If Exclusive is used, value cannot be equal to the definition. If Inclusive, can be equal to, but not less than, this definition.

All numeric and dates

pattern

A regular expression defining the allowed values.

All

totalDigits

Defines the maximum number of digits allowed.

Integers

whiteSpace

Defines how tabs, spaces, and line breaks are handled. Can be preserve (no changes), replace (tabs and line breaks are converted to spaces) or collapse (multiple spaces, tabs, and line breaks are converted to one space.

Strings and all binaries

A practical example of a restriction can be found in the MSN Search Web Service WSDL. Look at the section that defines SafeSearchOptions.

    <xsd:simpleType name="SafeSearchOptions">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="Moderate" />
            <xsd:enumeration value="Strict" />
            <xsd:enumeration value="Off" />
    </xsd:restriction>
</xsd:simpleType>

In this example, the SafeSearchOptions data type is based on a string data type. Unlike a regular string, however, the value that SafeSearchOptions takes is restricted by the restriction element. In this case, the several enumeration elements that follow. SafeSearchOptions can only be what is given in this enumeration list. That is, SafeSearchOptions can only have a value of "Moderate", "Strict", or "Off".

Restrictions are not the only reason to use a simple type. There can also be two other elements in place of restrictions. The first is a list. If an element is a list, it means that the value passed to it is a list of space-separated values. A list is defined with the list element followed by an attribute named itemType, which defines the allowed data type. For example, this example specifies an attribute named listOfValues, which comprises all integers.

    <xsd:simpleType name="listOfValues">
        <xsd:list itemType="xsd:integer" />
    </xsd:simpleType>

The second is a union. Unions are basically a combination of two or more restrictions. This gives you a greater ability to fine-tune the allowed value. Back to our age example, if our service was for a hospital's pediatrics ward that admits only those under 18 years old, we can restrict the value with a union.

    <xsd:simpleType name="Age">
        <xsd:union>
            <xsd:simpleType>
                <xsd:restriction base="decimal">
                        <xsd:minInclusive value="0" />
                </xsd:restriction>
            </xsd:simpleType>
            <xsd:simpleType>
                <xsd:restriction base="decimal">
                        <xsd:maxExclusive value="18" />
                </xsd:restriction>
            </xsd:simpleType>
        </xsd:union>
    </xsd:simpleType>

Finally, it is important to note that while simple types are, especially in the case of WSDLs, used mainly in the definition of elements, they can be used anywhere that requires the definition of a number. For example, you may sometimes see an attribute being defined and a simple type structure being used to restrict the value.

Complex Type

Generically, a complex type is anything that can have multiple elements or attributes. This is opposed to a simple type, which can have only one element. A complex type is represented by the element complexType in the WSDL. The most common use for complex types is as a carrier for objects in SOAP transactions. In other words, to pass an object to a SOAP service, it needs to be serialized into an XSD complex type in the message.

The purpose of a complexType element is to explicitly define what other data types make up the complex type. Let's take a look at a piece of Google's WSDL for an example:

    <xsd:complexType name="ResultElement">
        <xsd:all>
            <xsd:element name="summary" type="xsd:string"/>
            <xsd:element name="URL" type="xsd:string"/>
            <xsd:element name="snippet" type="xsd:string"/>
            <xsd:element name="title" type="xsd:string"/>
            <xsd:element name="cachedSize" type="xsd:string"/>
            <xsd:element name=
                        "relatedInformationPresent" type="xsd:boolean"/>
            <xsd:element name="hostName" type="xsd:string"/>
            <xsd:element name=
                        "directoryCategory" type="typens:DirectoryCategory"/>
            <xsd:element name="directoryTitle" type="xsd:string"/>
        </xsd:all>
    </xsd:complexType>

First thing to notice is how the xsd: namespace is used throughout types. This denotes that these elements and attributes are part of the XSD specification.

In this example, a data type called ResultElement is defined. We don't exactly know what it is used for right now, but we know that it exists. An element tag denotes complex type's equivalent to an object property. The first property of it is summary, and the type attribute tells us that it is a string, as are most properties of ResultElement. One exception is relatedInformationPresent, which is a Boolean. Another exception is directoryCategory. This has a data type of DirectoryCategory. The namespace used in the type attribute is typens. This tells us that it is not an XSD data type. To find out what it is, we'll have to look for the namespace declaration that declared typens.

PHP Web 2.0 Mashup Projects: Practical PHP Mashups with Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo! Create practical mashups in PHP grabbing and mixing data from Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo!, Last.fm, and 411Sync.com
Published: September 2007
eBook Price: £14.99
Book Price: £24.99
See more
Select your format and quantity:

Namespace definitions are usually at the top root element tag. Looking there, we find our namespace is indeed defined:

    <definitions name="GoogleSearch"
                targetNamespace="urn:GoogleSearch"
                xmlns:typens="urn:GoogleSearch"

The name of the root element is GoogleSearch, and that is the target of typens. The value of the declaration is this document itself. Therefore, DirectoryCategory must be defined elsewhere in this document.

Looking further down the WSDL, we find the definition:

    <xsd:complexType name="DirectoryCategory">
        <xsd:all>
            <xsd:element name="fullViewableName" type="xsd:string"/>
            <xsd:element name="specialEncoding" type="xsd:string"/>
        </xsd:all>
    </xsd:complexType>

DirectoryCategory appears to be another complex type. Two string elements comprise the object.

The point of looking at this is to understand that basically anything can be a property of the main class. Most properties of objects will be XSD built in data types, but it is perfectly legal to hold other complex types as properties.

Arrays

The last common data type that you'll encounter is an array. Arrays in WSDL are a little unusual. Up to this point, WSDL has been using XSD to define data types. XSD is primarily used to define a document structure, unlike WSDL, which is used to define a network transport payload.

In the latter, passing arrays is crucial, while in the former, it is less so. Not entirely surprising then, that in XSD, declaring an array is not a straight forward and easy thing to do.

To keep the writing of WSDL as simple as possible, WSDL drops the use of XSD when declaring arrays, and instead, uses SOAP's array structures to define its own arrays. An array is declared in WSDL by creating a complex type and restricting it (using the same restriction element found in simple types) to the SOAP array data type. After that, the data type of each element of the array is declared.

In this example, an array of integers is declared.

    <xsd:complexType name="ArrayOfInteger">
        <xsd:complexContent>
            <xsd:restriction base="soapenc:Array">
                <xsd:attribute ref="soapenc:arrayType" wsdl:
                                    arrayType="integer[]"/>
            </xsd:restriction>
        </xsd:complexContent>
    </xsd:complexType>

The declaration begins with the complexType tag. We name the array with the name attribute. WSDL convention states that the name of arrays should be in the format of "ArrayOfxxxx" where xxxx is the type of items in the array, be they one of the built-in data types or other specialized types defined here in the types element.

Remember, in types, we are merely defining the available data types in the web service. We are not tying them to any operation just yet. If the web service has more than one operation that uses arrays of integers, the operations definitions later will just reuse this one array. Therefore, it is perfectly legal to have a generic name like ArrayOfInteger or ArrayOfDate, etc.

A tag named complexContent is the first and only child. Then we begin with the restriction. This is where the divergence from XSD takes place. First, note the base attribute. Unlike the previous restriction tags we've seen, this one does not have the xsd: namespace. Instead, as WSDL uses SOAP encoding for arrays, the base attribute now uses the soapenc: namespace followed by the SOAP structure named Array.

Next is an XSD attribute to specify the encoding and a WSDL attribute named arrayType that defines the data type. The data type is followed by open and close brackets. This example uses integers. An array of strings would have string[], and an array of objects would have the name of the complex type followed by the brackets.

The data types are probably the most important things you will need to understand from the WSDL apart from the actual operations themselves, which are defined later. This section lets us know what data format we need to pass into operation parameters and what we can expect back.

This has been just an overview of how simple type elements are structured. For a reference of every built-in data type and restrictions supported, see the official XSD data type recommendation at http://www.w3.org/TR/xmlschema-2/.

message Element

This is the second of the four children of the definitions root element. In this element, we gather up the data types and bundle them together to prepare them for use later in portType, where we actually define the available service operations. Message is merely a layer of abstraction between the data types and portType. Think of the items in types as data types and message assigns these data types to parameters. Later, we'll assign these parameters to actual operations in portType.

The format of messages depends on what is used in the SOAP binding, later on in the binding element. The binding also affects how we create the SOAP message later when we are actually writing the SOAP message body. We will see this in more detail later, however, for now, know that the style attribute in the SOAP binding element can be either rpc or Document.

RPC Binding

If the binding is rpc, which stands for Remote Procedure Call, like in XML-RPC, messages are merely an element named message, each with one or more part elements. Each part is the name of an item in types.

The Google WSDL provides us with another good example:

    <message name="doGoogleSearch">
        <part name="key" type="xsd:string"/>
        <part name="q" type="xsd:string"/>
    …
        <part name="oe" type="xsd:string"/>
    </message>

The WSDL defines a message called doGoogleSearch. It's made up of approximately 10 part elements. These part elements take two attributes name, which defines the parameter name, and type, which is the data type. In doGoogleSearch, a part named key is a string. Another named q is also a string, and so forth.

    <message name="doGoogleSearchResponse">
        <part name="return" type="typens:GoogleSearchResult"/>
    </message>

Another message named doGoogleSearchResponse is defined. The parameter returned is named return and it is a GoogleSearchResult object. In doGoogleSearch, the data types were regular XSD built-in types, they are not mentioned in types. However, GoogleSearchResult is obviously not an XSD standard data type, so we would have to look back in types to get the object definition.

Document Binding

Another common value for the binding elment is document. By fortunate chance, the Microsoft Live Search API gives us an example of document binding. We can use the messages in this WSDL to see the difference:

    <wsdl:message name="SearchMessage">
        <wsdl:part name="parameters" element="tns:Search" />
    </wsdl:message>

Here, the message element is the same as the rpc version. The part element and name parameters are also present. However, instead of a type attribute, there is an element attribute. This is the operation name that we will call later on when we write our SOAP request.

How do we know what parameters Search needs? We look back up to the types section. In here, we find a data type of element that has the same name as the element in SearchMessage:

    <xsd:element name="Search">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element minOccurs="1" maxOccurs="1"
                name="Request" type="tns:SearchRequest" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

In it, there are some data rules, but this element points to another data type called SearchRequest. We look again in the data types for SearchRequest:

    <xsd:complexType name="SearchRequest">
        <xsd:sequence>
                <xsd:element minOccurs="1" maxOccurs="1"
                    name="AppID" type="xsd:string" />
                <xsd:element minOccurs="1" maxOccurs="1"
                    name="Query" type="xsd:string" />
                <xsd:element minOccurs="1" maxOccurs="1"
                    name="CultureInfo" type="xsd:string" />
                        …
        </xsd:sequence>
    </xsd:complexType>

Finally, we see that SearchRequest is a complex type, and we see which elements make up this object, and hence, which parameters the Search operation will need.

This type of document hopping is all too common in the WSDL world. Fortunately, the basic elements and theory of WSDL have a bit of logic and common sense behind them. It may take a bit of diligence, but you can eventually find the operation name and parameters in a SOAP-based service.

portType Element

Finally, we get to the definition of the actual web service operations. This is done in the portType element. Think of operations as the actual functions available in a web service. A portType element is the parent element for a group of operations. portType is merely a way to categorize sets of operations. For example, a web service may have one group of operations used solely by partner sites and another group of services used only be customers. The group of operations used by partners may be under a single portType element named PartnerOperations while operations used by customers are grouped under another portType named CustomerOperations. Most simple web services, though, will just have one portType element. This is true of the Google and Microsoft Live Search APIs we will look at.

Each operation is defined with the operation element. Each operation can be either of the following four types:

  • One-way: The client sends an input message to the server.
  • Request-Response: The client sends an input message to the server. The server responds with an output message.
  • Solicit-Response: The server sends an output message to the client. The client responds with an input message.
  • Notification: The server sends an output message to the client.

Out of the four, the vast majority used in web services is the Request-Response method. Even if the web service has an operation that just takes an input to manipulate data on the server, best practices state that a service should send a success or failure response message back to the client. This operation type defines the necessary children elements for the operation element. For Request-Reponses, both an input element specifying the message to be used must be defined, and an output element specifying the associated message needs to be included. Let's take another look at the Google SOAP Search API WSDL.

    <portType name="GoogleSearchPort">
        <operation name="doGetCachedPage">
            <input message="typens:doGetCachedPage"/>
            <output message="typens:doGetCachedPageResponse"/>
        </operation>
        ...
    </portType>

The first operation defined is doGetCachedPage. It takes an input message of doGetCachedPage and returns a doGetCachedPageResponse message as the output. This tells us that to do a doGetCachedPage operation against the Google SOAP Search service, we need to pass whatever parameters are specified in the doGetCachedPage message. If successful, we will get data back that is in the form defined in the doGetCachedPageResponse message.

Think of the relationship as "types make up messages, and messages make up operations".

SOAP and PHP 5

PHP Web 2.0 Mashup Projects: Practical PHP Mashups with Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo! Create practical mashups in PHP grabbing and mixing data from Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo!, Last.fm, and 411Sync.com
Published: September 2007
eBook Price: £14.99
Book Price: £24.99
See more
Select your format and quantity:

binding Element

The last element in a WSDL we should note is the binding element. In WSDL, these are extensions to SOAP. This element ties the operations defined in portType to specific SOAP actions. Unless you are making your own SOAP client or writing a WSDL document, you do not need too much detail about this. However, it is nice to know what exactly is going on here.

The binding from WSDL portType to SOAP actions is declared in the type attribute of the binding element. The value of this should point back to a name of a portType element.

    <binding name="GoogleSearchBinding" type="typens:GoogleSearchPort">
        <soap:binding style="rpc" transport=
                                        "http://schemas.xmlsoap.org/soap/http"/>
        <operation name="doGetCachedPage">
          <soap:operation soapAction="urn:GoogleSearchAction"/>
          <input>
            <soap:body use="encoded" namespace="urn:GoogleSearch"
                encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
          </input>
          <output>
            <soap:body use="encoded" namespace="urn:GoogleSearch"
                encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
          </output>

The children elements are basically metadata details for the SOAP transactions. We talked about the soap:binding element when we described messages. The style attribute here is where rpc or document is set.

The important thing you should pay attention to are the operation elements. These elements expose the portType operations to SOAP by mapping them directly to a SOAP operation. If the portType operations are not listed here, they will not be available to the caller. Underneath this, can be body elements. These elements provide SOAP-specific metadata to the operation.

The use attribute here is either encoded or literal. In combination with the binding's style attribute, this determines how the messages section and SOAP body elements are created.

The only thing you may run across in the course of making a mashup, especially with proprietary data, is the use of SOAP headers. SOAP headers often contain information about the transaction itself. One of the common uses for headers is authentication data. You may have to supply some credentials to the service before it fulfills your request. In the WSDL, a header requirement is defined in the input element here in the bindings. Like the messages definition, it will state the data type required with the part attribute.

    <input>
        <soap:header message="tns:submitPassword" part=
                "xsd:string" use="literal"/>
    <soap:body

Then, you can trace back up the WSDL to the message section to find out the exact element name you need to pass in the SOAP header.

    <message name="submitPassword">
    <part name="password_header" element="Password" />

The element attribute is the key. It states the name of the element you need to pass in the SOAP header. In this example, this service expects a SOAP header with an element of Password that is a string to be passed with the SOAP message.

We won't run across headers in the Google and Microsoft Live Search APIs, but be aware of them if you do run across one in the WSDL.

service Element

Lastly, we come to the service element. This element gives us the specific location of where the SOAP action point is for each port. Each port will have its own element here, followed by the SOAP address tag that points back to the service. Google's service element looks like this:

    <service name="GoogleSearchService">
        <port name="GoogleSearchPort" binding="typens:
        GoogleSearchBinding">
            <soap:address location="http://api.google.com/search/beta2"/>
    </port>
    </service>

The main thing this tells us is that all operations that happen in GoogleSearchPort occur at the URL http://api.google.com/search/beta2. We may need to use this information later if we hit a service directly.

The SOAP Message

Being able to decipher a WSDL gives us the rules that we need to write a SOAP message to a service. We can now call operations against a service, pass parameters that the service needs in the data type that it expects, and prepare for a response from the server.

The structure of a SOAP message is fairly straightforward. Further, SOAP utilizes the same structure for request and responses. An element named Envelope is the root element for the whole message. Within that, an element named Header holds routing data for the message. A Body element holds the message content. This may be the parameters we pass when we make a request, or the service results when we get a response. Finally, a Fault element gives information on any errors that occurred during execution. Structurally, a SOAP message looks like this:

    <?xml version="1.0"?>
    <soap:Envelope
        xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
        soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
        <soap:Header>
            ...
          </soap:Header>
          <soap:Body>
        ...
                <soap:Fault>
    ...
              </soap:Fault>
            </soap:Body>
    </soap:Envelope>

Again, we will not take too detailed a look into this. Luckily for us, PHP's SoapClient, which we will investigate later, hides a lot of SOAP details for us. However, knowing how a SOAP request is structured is essential to using the SOAP client and troubleshooting.

Envelope

The Envelope element identifies the XML document as a SOAP message. There are two things it must do. First, and absolutely essential, is to declare the SOAP namespace. Second, the encoding style must be set in the document. Both are done through attributes of the Envelope element.

    <soap:Envelope
        xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
        soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">

If there are other namespaces that the SOAP messages uses, they must be declared here also. For example, a proper request to Google SOAP Search API would need to declare XSD data types when we define parameters. In order to do this, we would declare the XSD data types in a namespace here in the Envelope element.

    <SOAP-ENV:Envelope
        xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:ns1="urn:GoogleSearch"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
        SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

Header

If the service requires any headers, they should be added in the SOAP header element. If headers are required, they will be noted in the documentation, or explicitly stated in the WSDL. SOAP headers are specific to the web service implementation. Therefore, each one needs to be namespace qualified.

In the previous password example, the service is expecting an element named password that is a string to be passed in the Header. We place this in the SOAP header like so:

    <soapenv:Header>
        <mysoap:password xmlns:mysoap="http://yourserviceURL">
    password
    </xmlns:mysoap>
    </soapenv:Header>

If the service does not require headers, we can omit the Header element. In the SOAP specifications, this element is optional.

Body

Finally, we get to the body of the SOAP message. Here is where we pass the request to the server and all the required parameters. What is included in this section and how it's structured is dictated entirely by the web service. Most notably, we refer back to the SOAP binding element in the WSDL for the exact structure of the body.

In most public web service cases, the schema is rather simple. The name of the operation you wish to call is a child element of the Body tag. Underneath that, the parameters are nested as elements.

In the most basic form, a body element will look like this:

    <soapenv:Body>
        <nameOfOperationToBeCalled>
            <parameterOne>Parameter One</parameterOne>
            <parameterTwo>23.39</parameterTwo>
            <parameterThree>true</parameterThree>
        </nameOfOperationToBeCalled>
    </soapenv:Body>

Let's see how the SOAP binding affects the creation of the messages.

RPC Binding

RPC binding needs the data types of the parameter passed in each parameter. We can look at how a request to the Google SOAP Search API is made:

    <soap-env:Body>
        <ns1:doGoogleSearch>
            <key xsi:type="xsd:string">Your Google License Key</key>
            <q xsi:type="xsd:string">Orange Tabbies</q>
            <start xsi:type="xsd:int">0</start>
            <maxResults xsi:type="xsd:int">10</maxResults>
              …
        </ns1:doGoogleSearch>
    </soap-env:Body>

The data type is declared in the type attribute. In Google's implementation, it calls upon the XSD and XSDI standards for the data types. These namespaces were declared back in the envelope element.

Document Binding

In document binding, the data types are not required to be part of the body. We can look at how to make a call against the Microsoft Live Search service to see how that works.

    <soap-env:Body>
        <ns1:Search>
            <ns1:Request>
                <ns1:AppID>Your MSN Search API Key</ns1:AppID>
                <ns1:Query>Orange Tabbies</ns1:Query>
                <ns1:CultureInfo>en-US</ns1:CultureInfo>
                …
            </ns1:Request>
        </ns1:Search>
    </soap-env:Body>

This looks very similar to the RPC binding version.ns1 is the Microsoft schema namespace, so that is required for all elements. Like RPC, the operation name serves as the parent element within Body. Each parameter name is a child element with the parameter value set as the value of the element. This time, though, there are no data types attributes.

Fault

Error reporting is standardized in SOAP through the Fault element. This element is passed by the server if there was a problem with the request. It always appears as a child of the Body element. Obviously, we won't have to deal with writing a fault when consuming web services. However, knowing about what comes back when something goes wrong is crucial to troubleshooting.

There are four children of Fault:

Child Element

Description

faultcode

One of four codes to identify the fault.

faultstring

A descriptive explanation of what went wrong.

faultactor

Where the fault occurred.

detail

A container for any application-specific error information about the body element

In SOAP 1.1, there are four possible fault codes:

faultcode

Description

VersionMismatch

Problem with the SOAP namespace declaration in the Envelope element.

MustUnderstand

A MustUnderstand attribute in the Header was not understood.

Client

The error is related to the client-end. The request was misformed.

Server

There was a server processing error. The request could not continue.

Now that we have some working knowledge of SOAP, WSDL, and XSD, we can put this to use to start writing PHP code.

Summary

In this article, we were introduced to SOAP, the most complex of the web service protocols so far. SOAP relies heavily on other standards like WSDL and XSD. We took a look at a WSDL document and learned how to figure out what web services are available from it, and what types of data are passed. Using web services from MSN, and Yahoo!, we would be exposed to three very big players in the web service game. If we use web services from them in the future, we'll know what type of documentation and support we can expect from each one.

About the Author :


Shu-Wai Chow

Shu-Wai Chow has worked in computer programming and information technology for the past eight years. He started his career in Sacramento, California, spending four years as the webmaster for Educaid, a First Union Company, and another four years at Vision Service Plan as an application developer. Through the years, he has become proficient in Java, JSP, PHP, ColdFusion, ASP, LDAP, XSLT, and XSL-FO. Shu has also been the volunteer webmaster and a feline adoption counselor for several animal welfare organizations in Sacramento.

He is currently a software engineer at Antenna Software in Jersey City, New Jersey, and is finishing his studies in Economics at Rutgers, the State University of New Jersey.

Born in the British Crown Colony of Hong Kong, Shu did most of his alleged growing up in Palo Alto, California. He lives on the Jersey Shore with seven very demanding cats, four birds that are too smart for their own good, a tail-less bearded dragon, a betta who needs her tank cleaned, a dermestid beetle colony, a cherished Fender Stratocaster, and a beloved, saint-like fiancé.

Books From Packt

JBoss Tools 3 Developers Guide
JBoss Tools 3 Developers Guide

Drupal 6 JavaScript and jQuery
Drupal 6 JavaScript and jQuery

Object-Oriented JavaScript
Object-Oriented JavaScript

Spring Web Flow 2 Web Development
Spring Web Flow 2 Web Development

Selling Online with Drupal e-Commerce
Selling Online with Drupal e-Commerce

Django 1.0 Website Development
Django 1.0 Website Development

Choosing an Open Source CMS: Beginner's Guide
Choosing an Open Source CMS: Beginner's Guide

jQuery UI 1.6: The User Interface Library for jQuery
jQuery UI 1.6: The User Interface Library for jQuery

 


 

 

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software