在前一篇技巧中,我解释了如何创建将请求发送到 Web 服务,然后显示结果的 XForms 表单。这里的不同之处在于,使用这项技术要求您使用符合 Web 服务期望的消息(比如 SOAP 消息)的实例。在本篇技巧中,我将解释如何可以创建另一个实例并与之交互,但是当到达某一时刻时,要提交该 SOAP 格式的实例。
本篇技巧假定您对 XForms 和 Web 服务有基本的了解。本文用到了 Internet Explorer 的 FormsPlayer 插件(请参阅 参考资料 进行下载)。
为了简单起见,我再一次使用普遍存在的天气示例,发送一个 ZIP 代码并接收当前的气温。实际的 Web 服务由 XMethods.net 提供(请参阅 参考资料 )。
初始请求只是一个 SOAP 消息,比如:
清单 1. SOAP 消息
<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>
lt;/SOAP-ENV:Body>
</SOAP-ENV:Envelope>
|
在该例中,不用使用表单直接对这条消息进行操作。您将创建另一个稍微友好一点的实例,然后在提交该实例之前,使用数据填充上述结构。
首先来创建一个基本的表单。XForms 表单由一个模型和一些控件组成,因此我们从操作它的基本实例和控件开始,如清单 2 所示。
清单 2. 基本的 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: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="guiInstance" xmlns="">
<inputData>
<zip>enter zip</zip>
</inputData>
</xforms:instance>
</xforms:model>
<xforms:input ref="instance('guiInstance')//zip">
<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>
|
该页面从定义所有相关名称空间开始,接着转向导入 FormsPlayer 对象及其名称空间。然后,您就可以进入表单本身,图 1 中显示了该表单。
从模型开始,当您为其做好准备时,该模型最终将既包含实例又包含提交信息。同时,您恰好已经创建了一个非常简单的实例来保存您正寻找的数据。这很可能就是来自您的遗留系统的一个复杂文档。在页面的结尾处,您已经定义了一个限制为 zip 元素的简单输入框。
图 1: 输入控件
现在,您将准备提交表单。
注意,我说的是“您将准备提交表单”,而不是“您将提交表单”。正如在第一篇技巧中那样,您必须处理这样一种情况,在该情况下,您需要为已经不存在的关联数据(Web 服务结果)创建控件(结果输出)。为了小心起见,可以创建一个通过一对
case 和一个
toggle 控制的开关,如清单 3 所示:
清单 3. 添加开关
...
</xforms:instance>
</xforms:model>
<xforms:switch>
<xforms:case id="request">
<h2>Enter your zip code</h2>
<xforms:input ref="instance('guiInstance')//zip">
<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:case>
<xforms:case id="response">
<h2>And the result is...</h2>
The zip code you requested is:
<xforms:output ref="instance('guiInstance')//zip" />
</xforms:case>
</xforms:switch>
</body>
</html>
|
每次只能显示一种情况(case)—— 默认情况下,显示第一种情况。要转向另一种情况,需要添加起
trigger 作用的
toggle ,如清单 4 所示:
清单 4. 添加触发器
...
<xforms:case id="request">
<h2>Enter your zip code</h2>
<xforms:input ref="instance('guiInstance')//zip">
<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>Get current temperature</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:toggle case="response" />
</xforms:action>
</xforms:trigger>
</xforms:case>
|
正如您在图 2 中可以看到的,触发器被表示为一个简单的按钮。
图 2: 触发器按钮
当用户单击该按钮,或者以其他方式激活触发器时,您可以获得第二种情况,一会儿我将展示给您。
首先来看一看第二个实例。
现在,即将添加第二个实例到页面。因为 Web 服务正在查找 XML,所以该实例就是 Web 服务正在查找的消息,如清单 5 所示:
清单 5. 添加第二个实例
...
<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">NO DATA SUBMITTED</zipcode>
</ns1:getTemp>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</xforms:instance>
<xforms:instance id="guiInstance" xmlns="">
<inputData>
<zip>enter zip</zip>
</inputData>
</xforms:instance>
</xforms:model>
...
|
这个难题的一个重要部分就是
zipcode 元素,通过将另一个
output 控件添加到
response 情况,您可以看见该元素的状态,如清单 6 所示:
清单 6. 查看提交的数据
...
<xforms:case id="response">
<h2>And the result is...</h2>
The zip code you requested is:
<xforms:output ref="instance('guiInstance')//zip" />
<br />
The zip code you are going to send is:
<xforms:output ref="instance('messages')//zipcode" />
</xforms:case>
...
|
如果输入一个邮政编码并单击触发器按钮,您可以看见事物的当前状态,如图 3 所示。
图 3. 监视提交的数据
显然,这无法奏效。您需要将请求的数据放入想要提交的实例中。
简而言之,当用户激活触发器时,您应该将数据从
guiInstance zip 元素复制到
messages zipcode 元素中。在进行复制时,值可以直接转换到表单中:
清单 7: 将值复制到消息实例中
...
<xforms:trigger style="display:block">
<xforms:label>Get current temperature</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:setvalue ref="instance('messages')//zipcode"
value="instance('guiInstance')//zip" />
<xforms:toggle case="response" />
</xforms:action>
</xforms:trigger>
...
|
当用户激活触发器时,该表单会将
messages 实例中
zipcode 元素的值设置为
guiInstance 实例中
zip 元素的值。要查看这一点,需要重载该表单并提交它(参见图 4)。
图 4. 设置 zipcode 元素的值
现在,您必须处理提交问题。
要提交 message 实例,需要创建作为模型一部分的
submission 元素,并从触发器发送它,如清单 8 所示:
清单 8. 创建 submission 元素
...
<xforms:instance id="guiInstance" xmlns="">
<inputData>
<zip>enter zip</zip>
</inputData>
</xforms:instance>
<xforms:submission id="getweather"
method="text-xml-post"
replace="instance"
ref="instance('messages')"
action="http://services.xmethods.net:80/soap/servlet/rpcrouter"
/>
</xforms:model>
<xforms:switch>
<xforms:case id="request">
...
<xforms:trigger style="display:block">
<xforms:label>Get current temperature</xforms:label>
<xforms:action ev:event="DOMActivate">
<xforms:setvalue value="instance('guiInstance')//zip"
ref="instance('messages')//zipcode"/>
<xforms:toggle case="response" />
<xforms:send submission="getweather"/>
</xforms:action>
</xforms:trigger>
</xforms:case>
<xforms:case id="response">
<h2>And the result is...</h2>
The temperature in zip code
<xforms:output ref="instance('guiInstance')//zip" />
is approximately
<xforms:output ref="instance('messages')//return" /> degrees.
</xforms:case>
</xforms:switch>
</body>
</html>
|
这样就创建了
submission 元素,从触发器发它,并提取返回的值以便显示。正如您在图 5 中可以看到的,您可以访问原始数据——因为它们仍然存在于原始实例中,而且您还能够将一个单独的实例提交给服务。
图 5. 最终结果
XForms 像 Web 服务客户机一样便利,因为它们能够发送和接收 XML,但将 Web 服务请求用作数据实例可能有些麻烦和不便。本篇技巧已经解释了如何创建一个实例用于操作数据,同时创建另一个实例用于发送和接收数据。您将了解:
- 创建基本的表单。
- 创建两个实例。
- 在提交实例之前,将数据从以前的实例迁移到另一个实例中。
- 提交请求。
- 接收响应。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 阅读本系列的第一篇技巧“
使用 XForms 发送和接收 Web 服务消息”,以查找有关该技术的更多信息(
developerWorks,2004 年 7 月)。
- 下载本教程中使用的
Internet Explorer FormsPlayer 插件。
- 获得关于
本技巧中使用的 Web 服务的更多信息,或者访问
XMethods 主页,获得其他大量公开可用的服务。
- 阅读 W3C 站点上的
XForms 规范。
- 阅读
developerWorks的文章,更多地了解 XForms ,可以阅读由 Joel Rivera 和 Len Taing 撰写的“
准备使用 XForms”(2002 年 12 月),或者阅读 Nicholas Chase 撰写的“理解 XForms” 教程(2004 年 1 月)。
- 阅读
the W3C SOAP primer,了解更多关于 SOAP 的信息。
- 阅读
developerWorks的
SOAP and Web services 新手指南。
- 在
developerWorks的
XML专区和
SOA and Web services专区,可以找到大量的文章、专栏、教程和技巧,还可以订阅
Web services/XML Tips 时事通讯。
- 在
developerWorks的
Developer Bookstore可以浏览大量关于 XML 的书籍。
Nicholas Chase 是 Studio B的作者,他参与了诸如 Lucent Technologies、Sun Microsystems、Oracle 和 Tampa Bay Buccaneers 等公司的 Web 站点的开发。Nick 曾经是一位高中物理教师、低放射性废弃设备管理员、在线科幻小说杂志的编辑、多媒体工程师和 Oracle 讲师。最近,他成为一家交互式通信公司的首席技术官,该公司位于美国佛罗里达州的克利尔沃特市,而且他还是几本有关 Web 开发的书籍的作者,其中包括 XML Primer Plus (Sams)。他目前正试图购买一个农场,以便与妻子一起饲养羊驼和鸡。他乐于听取读者的意见,您可以通过 nicholas@nicholaschase.com与他联系。