This tip assumes a basic familiarity with XForms and with Web services. It uses the FormsPlayer plug-in for Internet Explorer (see Resources to download it).
In this tip, I’m going to show you how to create an XForms form that sends a request to a Web service and then displays the results. To keep things simple, I’m going to use the ubiquitous weather example, sending a ZIP code and receiving the current temperature. The actual Web service is provided by XMethods.net (see Resources).
The initial request is just a SOAP message, such as:
Listing 1. Initial SOAP request
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTemp xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<zipcode xsi:type="xsd:string">02134</zipcode>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
|
You’ll use the XForms form to provide a value for the zipcode element. When you submit it to the service, you’ll get a response such as:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:int">86</return>
</ns1:getTempResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
|
You’ll also use the form to retrieve the return value and display it.
Start by creating the basic form. An XForms form consists of a model and controls. The model includes information such as the instance, which represents the data to be displayed and submitted, and the submission, which includes information on where and how to send the data:
Listing 3. A basic XForms form
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:ns1="urn:xmethods-Temperature"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<head>
<title>XForms and Web Services</title>
</head>
<body>
<object id="FormsPlayer"
classid="CLSID:4D0ABA11-C5F0-4478-991A-375C4B648F58">
<b>FormsPlayer has not loaded. Please check your installation.</b>
</object>
<?import namespace="xforms" implementation="#FormsPlayer" ?>
<xforms:model id="WeatherService">
<xforms:instance id="messages">
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTemp xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<zipcode xsi:type="xsd:string">02134</zipcode>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</xforms:instance>
<xforms:submission id="getweather"
method="text-xml-post"
replace="instance"
action="http://services.xmethods.net:80/soap/servlet/rpcrouter"
/>
</xforms:model>
</body>
</html>
|
First, tell Internet Explorer to load the FormsPlayer object. If it’s not loaded, the browser displays the contents of the tag, telling the user to download and install it.
Next you have the model, which includes the instance and the submission. The instance is not just the data to be displayed; it’s also the data that will eventually be submitted, so it’s identical to the SOAP request presented earlier in Listing 1.
You’ll get a closer look at the submission itself when you actually submit the data.
In the meantime, you need to actually create the form:
...
<xforms:model id="WeatherService">
<xforms:instance id="messages">
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTemp xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<zipcode xsi:type="xsd:string">02134</zipcode>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</xforms:instance>
<xforms:submission id="getweather"
method="text-xml-post"
replace="instance"
action="http://services.xmethods.net:80/soap/servlet/rpcrouter"
/>
</xforms:model>
<xforms:input ref="instance('messages').//zipcode">
<xforms:label>Zip code: </xforms:label>
<xforms:hint>Enter a zip code and submit the form for the current
temperature in that area.</xforms:hint>
</xforms:input>
</body>
</html>
|
Figure 1: The simple text control

When the user changes the value in this control, it changes the corresponding node of the XML contained in the instance. So if you were to change the value in that field to, say, 10314, the instance document would look like this in memory:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTemp xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<zipcode xsi:type="xsd:string">10314</zipcode>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
|
It is this document that gets submitted to the service. Before you get that far, however, you need to look at the state of the form.
When you submit the form, you will actually replace the instance document with a second instance document that has a different structure, so in order to display information from it, you will need controls based on that structure instead of the original one. You can’t, however, include both of these controls on the page at the same time, because one of them will always refer to a nonexistent node, causing an error. To get around this problem, you need to create a situation in which only one set appears at a time. You can do that with a switch:
...
</xforms:model>
<xforms:switch id="switch1">
<xforms:case id="requestGUI">
<xforms:input ref=".//zipcode">
<xforms:label>Zip code: </xforms:label>
<xforms:hint>Enter a zip code and submit the form for the current
temperature in that area.</xforms:hint>
</xforms:input>
<xforms:trigger style="display:block">
<xforms:label>Change to results case</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:toggle case="responseGUI" />
</xforms:action>
</xforms:trigger>
</xforms:case>
<xforms:case id="responseGUI">
Results go here.
<xforms:trigger>
<xforms:label>Change to request case</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:toggle case="requestGUI" />
</xforms:action>
</xforms:trigger>
</xforms:case>
</xforms:switch>
</body>
</html>
|
Here there are two cases. The first is displayed by default. To this case you add a trigger, or button, that activates when you click it, as in Figure 2.

When it does, it executes everything in the action element, which in this case is to toggle the case to the responseGUI state. This tells the browser to display only that case, as in Figure 3:

Using this form, the user can toggle back and forth by clicking the buttons. Now you need to add the form submission.
Of course, the form isn’t much good to you this way. What you ultimately want is to switch to the results case after you submit the form. You can do that by adding the submission to the action:
Listing 7. Add the submission to the action
...
<xforms:trigger style="display:block">
<xforms:label>Get current temperature</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:send submission="getweather" />
<xforms:toggle case="responseGUI" />
</xforms:action>
</xforms:trigger>
...
|
This simply tells the browser to execute the submission getweather when the user clicks the button. Now, when you created the submission, you added some information to it:
Listing 8. Specify the submission as an XML post
...
<xforms:submission id="getweather"
method="text-xml-post"
replace="instance"
action="http://services.xmethods.net:80/soap/servlet/rpcrouter"
/>
...
|
This submission specifies that you’re submitting it as an XML post, which is perfect for a SOAP message, and that you want to replace the instance. This way, when it comes back, the instance looks something like Listing 9:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:int">86</return>
</ns1:getTempResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
|
To see the results, you need to retrieve them from within the resultGUI case:
Listing 10. Retrieve the results
<xforms:case id="responseGUI">
<xforms:output ref="instance('messages')//return"
style="width:40ex;display:block;">
<xforms:label>Current Temperature:</xforms:label>
</xforms:output>
</xforms:case>
...
|
This way, when you submit the form, you get the resulting temperature, as in Figure 4.

Because an XForms form sends and receives XML documents, it makes an excellent Web services client. In this tip, I showed you the basic process of using an XForms form to request information from a Web service. The process looked like this:
- The browser displays information from the instance document, which is structured as a SOAP request.
- The browser sends the instance document (including the ZIP code) to the Web service.
- The Web service sends a response (including the temperature) to the browser, which uses it to replace the original instance document.
- The browser switches to a second set of controls, which display the information returned by the Web service.
