级别: 中级 Nicholas Chase (nicholas@nicholaschase.com)Studio B
2004 年 9 月 01 日 将 XForms 表单用作 Web 服务客户提供了许多方便,因为它使发送和接收 XML 文档变得非常简单,但是,如果不希望发送整个数据实例,又该怎么办呢?这篇技巧将解释如何创建包含 SOAP 消息和其他数据的实例,然后,在提交时只发送 SOAP 消息。
在上一篇技巧中,您已经看到了 XForms 表单是如何轻松发送 Web 服务请求和接收响应,可是,在这些示例中,都是将整个实例发送给 Web 服务。但这种情况不一定符合您的计划。比如,SOAP 消息可能是一个更大的、包含其他相关数据的实例文档的一部分。在这篇技巧中,我们将围绕一个实例,向您展示如何创建 XForms 表单,该实例同时包含 SOAP 消息和其他数据,但在提交时,只发送 SOAP 消息。本文假设您对 XForms 有基本的了解,并且安装了 FormsPlayer XForms 客户机。(要获得更多信息,请参阅
参考资料。)
实例
首先创建包含实例的基本表单,如清单 1 所示:
清单 1. 基本表单
<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="weatherInstance" >
<data>
<employees>
<emp id="1">
<name>Nick</name>
<zip>10314</zip>
</emp>
<emp id="2">
<name>Troy</name>
<zip>90210</zip>
</emp>
<emp id="3">
<name>Bob</name>
<zip>34652</zip>
</emp>
</employees>
<soapmessage>
<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>
</soapmessage>
</data>
</xforms:instance>
</xforms:model>
</body>
</html>
|
该实例包括两个基本部分:
employees 数据和包含在
soapmessage 元素中的 SOAP 消息。在发送 SOAP 消息之前,将使用
employees 数据填充表单。为此,需要添加一个
select1 控件表示可供选择的雇员,如清单 2 所示:
清单 2. 添加一个 select1 菜单
...
</xforms:model>
<xforms:select1 appearance="minimal"
ref="instance('weatherInstance')//zipcode">
<xforms:label>Choose Employee</xforms:label>
<xforms:itemset nodeset="instance('weatherInstance')//emp">
<xforms:label ref="name"/>
<xforms:value ref="zip"/>
</xforms:itemset>
</xforms:select1>
</body>
</html>
|
该空间循环遍历每个
emp 元素,并创建图 1 所示的下拉菜单。
图 1: 基本数据控件
因为已经将
select1 元素的
ref 属性指向 SOAP 消息的
zipcode 元素,所以只需修改下拉菜单,向 Web 服务请求中添加适当的值即可。
在提交之前,需要填充表单的其他部分。
结构化表单
该项目的目标是创建一个表单,提交 SOAP 消息,然后检索 SOAP 响应并显示结果。为此,需要添加提交触发器按钮和读取返回数据的能力,如清单 3 所示:
清单 3. 完成表单
...
</data>
</xforms:instance>
</xforms:model>
<xforms:switch id="switch1">
<xforms:case id="requestGUI">
<xforms:select1 appearance="minimal"
ref="instance('weatherInstance')//zipcode">
<xforms:label>Choose Employee</xforms:label>
<xforms:itemset nodeset="instance('weatherInstance')//emp">
<xforms:label ref="name"/>
<xforms:value ref="zip"/>
</xforms:itemset>
</xforms:select1>
<xforms:trigger style="display:block">
<xforms:label>Get sensor ambient temperature</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:send submission="getweather" />
<xforms:toggle case="responseGUI" />
</xforms:action>
</xforms:trigger>
</xforms:case>
<xforms:case id="responseGUI">
<xforms:output ref="instance('weatherInstance')//return">
<xforms:label>Employee local temperature:</xforms:label>
</xforms:output>
</xforms:case>
</xforms:switch>
</body>
</html>
|
这里将表单分成两种情况,因为为控件提供数据的实例在提交前后是不同的。首先来看第一种情况,表单中包括雇员数据控件和
trigger 按钮。当用户单击触发器时,浏览器将发送
getweather 提交(后面创建),并切换到
responseGUI 状态,在新的结构中查找数据。一旦进入
responseGUI 状态,浏览器就会显示
return 元素中的气温值。
现在来创建实际的提交元素。
创建提交元素
为了提交表单,需要创建一个
submission 元素。该
submission 元素不但规定了数据发送到何处(通过
action 属性),还规定了要发送哪些数据,以及如何处理返回的数据。如清单 4 中所示的
submission 元素:
清单 4. 简单的 submission 元素
<xforms:submission method="text-xml-post"
action="http://services.xmethods.net:80/soap/servlet/rpcrouter" />
|
这个元素可以发挥一定的效用,但还不够完美。与传统的 HTML 表单相同, XForms 客户,或者本例中的浏览器,将整个实例发送给 action 中规定的 URL,然后用接收的响应代替整个页面。但这并不是我们想要的结果。我们希望只发送
soapmessage 元素中的内容,返回响应时只替换实例,而保持表单的其他部分不变。您可以在
submission 元素中完成操作,如清单 5 所示:
清单 5. submission 元素
...
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</soapmessage>
</data>
</xforms:instance>
<xforms:submission id="getweather" method="text-xml-post"
ref="instance('weatherInstance')//soapmessage/*"
replace="instance"
action="http://services.xmethods.net:80/soap/servlet/rpcrouter"
/>
</xforms:model>
|
submission 元素中规定只发送
soapmessage 元素的内容,收到响应时应该只替换实例而不是整个文档。
注意,虽然提交的只是实例的一部分,但当 Web 服务发回响应时,将替换整个实例,这是个一锤子买卖。为了避免这种情况,通过使用
replace="none" ,可以指定不使用返回的消息替代任何东西,但这仅适用于提交本身很重要而响应不重要的情况。
结束语
XForms 表单允许您创建包含 SOAP 消息的实例,但实例也可以包含其他数据。比如,在该例中,创建的表单在实例中使用其他来源的数据填充实际的 SOAP 消息。为此,您可以创建
submission 元素,指定实例的哪一部分需要发送。也可以使用
submission 元素说明如何处理返回的数据。
参考资料
关于作者  | |  | Nicholas Chase 是
Studio B 的作者,曾参与过许多公司网站的开发,其中包括 Lucent
Technologies、Sun Microsystems、Oracle 和 Tampa Bay Buccaneers。Nick 曾经做过高中物理教师、低级放射性废弃设备管理员、在线科幻杂志的编辑、多媒体工程师以及 Oracle 教员。最近,他在担任美国佛罗里达州克利尔沃特市一家交互通信公司的首席技术官,同时,他还是几本 Web 开发书籍的作者,其中包括
XML
Primer Plus(Sams)。目前,他正准备购买一座农场,打算和妻子饲养羊驼和小鸡。他很想听到读者的意见,您可以通过
nicholas@nicholaschase.com与他联系。
|
对本文的评价
|