Unlike traditional HTML forms, which are typically designed to either get information from or give information to the user, Web services are ultimately designed to provide information to an application; the user is almost an afterthought. This means that while it's generally sufficient to submit an HTML form to a single location and get a response, you often need to submit a request to a Web service and then use the response as the basis for a second request.
In this tip, you'll create an XForms form that provides information on a series of temperature sensors. The form takes a sensor identifier and submits it to a Web service that returns the zip code for that sensor. The form then automatically submits the zip code to a second service that provides the ambient temperature at the location that corresponds to that zip code. This tip assumes that you are generally familiar with XForms and that you have the FormsPlayer XForms client installed. (See the Resources for more information.)
Start by creating the basic form (shown in Listing 1), into which the user enters a sensor ID:
Listing 1. The 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: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="sensorInstance">
<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:getZip xmlns:ns1="urn:example-sensorZip"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<sensorId xsi:type="xsd:string"></sensorId>
</ns1:getZip>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</xforms:instance>
</xforms:model>
<xforms:input ref="instance('sensorInstance')//sensorId">
<xforms:label>Sensor ID: </xforms:label>
<xforms:hint>Enter the ID for the sensor whose ambient
temperature you want to check.</xforms:hint>
</xforms:input>
</body>
</html>
|
Here you have a simple form that enables the user to enter a value, as you can see in Figure 1. That value represents the contents of the sensorId element in the sensorInstance instance. The sensorInstance just happens to be in the form of a SOAP request, which you can then send to a Web service to get a response.
Figure 1: The basic form
Submitting to the first service
The first part of the form takes the sensor ID and submits it to a Web service that returns a zip code. To make that happen, you have to add a submission element and a trigger that sends it, as shown in Listing 2.
Listing 2. Submitting the form
...
<xforms:model id="WeatherService">
<xforms:instance id="sensorInstance">
<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:getZip xmlns:ns1="urn:example-sensorZip"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<sensorId xsi:type="xsd:string"></sensorId>
</ns1:getZip>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</xforms:instance>
<xforms:submission id="getzip"
method="text-xml-post"
replace="instance"
ref="instance('sensorInstance')"
action="http://www.nicholaschase.com/sensors/getZipService.php"
/>
</xforms:model>
<xforms:switch id="switch1">
<xforms:case id="requestGUI">
<xforms:input ref="instance('sensorInstance')//sensorId">
<xforms:label>Sensor ID: </xforms:label>
<xforms:hint>Enter the ID for the sensor whose ambient
temperature you want to check.</xforms:hint>
</xforms:input>
<xforms:trigger style="display:block">
<xforms:label>Get sensor ambient temperature</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:send submission="getzip" />
<xforms:toggle case="responseGUI" />
</xforms:action>
</xforms:trigger>
</xforms:case>
<xforms:case id="responseGUI">
<xforms:output ref="instance('sensorInstance')//return">
<xforms:label>Sensor zip code:</xforms:label>
</xforms:output>
</xforms:case>
</xforms:switch>
</body>
</html>
|
When you click the trigger button, two things happen. First, the browser sends the getzip submission. This submission is defined in the model using the submission element, which determines which data gets submitted and where it goes. In this case, you're sending the sensorInstance data to a service, which returns a SOAP message with the response. The actual zip code is in the return element.
After sending the submission, the form changes cases from the requestGUI, which shows the original form, to the responseGUI, which shows the returned data (see Figure 2).
Figure 2: The initial response
Now that you have the zip code, you have to find a way to send it to the weather service. Start by creating an instance to submit to that service, as shown in Listing 3:
Listing 3. Add the second instance
...
<xforms:model id="WeatherService">
<xforms:instance id="sensorInstance">
<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:getZip xmlns:ns1="urn:example-sensorZip"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<sensorId xsi:type="xsd:string"></sensorId>
</ns1:getZip>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</xforms:instance>
<xforms:instance id="weatherInstance">
<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"></zipcode>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</xforms:instance>
<xforms:submission id="getzip"
method="text-xml-post"
replace="instance"
ref="instance('sensorInstance')"
action="http://www.nicholaschase.com/sensors/getZipService.php"
/>
<xforms:submission id="getweather"
method="text-xml-post"
replace="instance"
ref="instance('weatherInstance')"
action="http://services.xmethods.net:80/soap/servlet/rpcrouter"
/>
</xforms:model>
...
|
The overall idea here is the same as what you've done so far: Create an instance that looks like a Web service request and then send it to a Web service as defined in the submission element. All you need to do now is to find a way to get the zip code returned by the first submission into the second instance before submitting the second instance. Fortunately, you can do that using the setvalue element:
Listing 4. Linking the two submissions
...
<xforms:submission id="getweather"
method="text-xml-post"
replace="instance"
ref="instance('weatherInstance')"
action="http://services.xmethods.net:80/soap/servlet/rpcrouter"
/>
</xforms:model>
<xforms:switch id="switch1">
<xforms:case id="requestGUI">
<xforms:input ref="instance('sensorInstance')//sensorId">
<xforms:label>Sensor ID: </xforms:label>
<xforms:hint>Enter the ID for the sensor whose ambient
temperature you want to check.</xforms:hint>
</xforms:input>
<xforms:trigger style="display:block">
<xforms:label>Get sensor ambient temperature</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:send submission="getzip" />
<xforms:setvalue value="instance('sensorInstance')//return"
ref="instance('weatherInstance')//zipcode"/>
<xforms:send submission="getweather" />
<xforms:toggle case="responseGUI" />
</xforms:action>
</xforms:trigger>
</xforms:case>
<xforms:case id="responseGUI">
<xforms:output ref="instance('sensorInstance')//return">
<xforms:label>Sensor zip code:</xforms:label>
</xforms:output>
<br />
<xforms:output ref="instance('weatherInstance')//return">
<xforms:label>Ambient sensor temperature:</xforms:label>
</xforms:output>
</xforms:case>
</xforms:switch>
</body>
</html>
|
If you look at the trigger, you'll realize that you've simply added more actions for the browser to perform. After submitting the first request, the sensorInstance instance will have a return element that holds the desired zip code. Using the setvalue element, you copy that value to the weatherInstance instance, which you subsequently submit. The results can then be shown in the page, as seen in Figure 3.
Figure 3. The final results
XForms is designed to separate the process of displaying data from the process of manipulating it, so it is very well suited to performing multiple submissions with a single request. This process involves creating an instance for each service, with each consisting of a SOAP request for that particular service. When the user causes an event such as activating a button, you can execute any number of actions, and because each instance can have its own submission, you can simply submit each instance in turn, moving data between instances using the setvalue element.
- Find out more about SOAP at the W3C's XML Protocol Working Group page.
- Read the W3C XForms Recommendation or the three-part Introduction to XForms series (Chris Herborth, developerWorks, September 2006).
- Download the FormsPlayer plug-in for Internet Explorer used in this tutorial.
- Learn more about submitting Web services requests with the developerWorks tip "Use XForms to send and receive Web services messages" (June 2004).
- Read our feature for those new to SOA and Web services.
- Find a broad array of articles, columns, tutorials, and tips at the developerWorks
XML and SOA and Web services zones. While you're at it, subscribe to the Web services/XML Tips newsletter.
-
Browse for books on these and other technical topics.
Nicholas Chase, a Studio B author, has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, and an Oracle instructor. More recently, he was the Chief Technology Officer of an interactive communications firm in Clearwater, Florida, USA, and is the author of several books on Web development, including XML Primer Plus (Sams). He's currently trying to buy a farm so he and his wife can raise alpacas and chickens. He loves to hear from readers and can be reached at: nicholas@nicholaschase.com.
Comments (Undergoing maintenance)





