在這篇技巧中,您將創建一個 XForms 表單,提供關於一系列溫度傳感器的信息。表單接受一個傳感器標識符,並將它提交給 Web 服務,該服務返回傳感器所在的郵政區號。然後,表單自動將郵政區號提交給第二個服務,再由該服務提供郵政區號對應地點的環境溫度。本技巧假設您對 XForms 具有一般性的了解,並且安裝了 FormsPlayer XForms 客戶程序。(有關的更多信息,請參閱 參考資料。)
基本的請求表單
首先創建一個基本表單(如清單 1 所示),用戶可以在該表單中輸入傳感器 ID:
清單 1. 基本的 XForms 表單
<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>
這是一個非常簡單的表單,它允許用戶輸入一個值,如圖 1 所示。該值代表 sensorInstance 實例中 sensorId 元素的內容。 sensorInstance 完全采用 SOAP 請求的格式,可以將它發送到 Web 服務並獲得響應。
圖 1: 基本表單
提交到第一個服務
表單的第一部分獲得傳感器 ID,並將它提交到返回郵政區號的 Web 服務。為此,必須添加一個 submission 元素和發送它的 trigger ,如清單 2 所示。
清單 2. 提交表單
...
<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>
單擊 trigger 按鈕時發生了兩件事。首先,浏覽器發送 getzip 提交。該提交在模型中使用 submission 元素定義,該元素確定了要提交的數據和提交的目的地。在本示例中,向服務發送的是 sensorInstance 數據,服務在響應中返回一個 SOAP 消息。真正的郵政區號在 return 元素中。
發送提交之後,表單從顯示原始表單的 requestGUI 切換到 responseGUI ,該界面顯示了返回的數據(如圖 2 所示)。
圖 2: 第一次響應
第二次提交
獲得郵政區號之後,必須找到一種方法將其發送給氣象服務。首先要創建一個實例,並將它提交給服務,如清單 3 所示:
清單 3. 添加第二個實例
...
<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>
...
總的思路和前面是一樣的:創建一個類似 Web 服務請求的實例,然後按照 submission 元素中的定義,將它發送到 Web 服務。現在要做的就是找到一種方法,取得第一次提交所返回的郵政區號,並在提交之前將它放到第二個實例中。所幸的是,可以使用 setvalue 元素完成這一工作:
清單 4. 連接兩次提交
...
<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>
觀察 trigger 就會發現,實際上只是添加了浏覽器要執行的動作。提交第一個請求之後, sensorInstance 實例中的 return 元素將包含需要的郵政區號。使用 setvalue 元素可以將這個值復制到 weatherInstance 實例中,然後提交該實例。結果顯示在如圖 3 所示的頁面中。
圖 3. 最終結果
結束語
XForms 的設計把顯示數據的過程與處理數據的過程分離了開來,因此非常適合在單次請求中執行多重提交。這個過程需要為每個服務創建一個實例,而且每個實例都包含特定服務的 SOAP 請求。當用戶觸發事件時(比如激活一個按鈕),可以執行任意多個動作,因為每個實例都可以有自己的提交,所以您要做的只是依次提交每個實例,並使用 setvalue 元素在實例間移動數據。