IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  XML | SOA and Web services  >

技巧:创建提交另一个实例的 XForms 表单

控制实例结构

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Nicholas Chase (nicholas@nicholaschase.com), 开发人员/作家, Studio B

2004 年 7 月 22 日

XForms 表单因为可以很容易地发送和接收 XML,所以赢得了很多的 Web 服务客户,但以这种方式使用它们可能会限制您对实例结构的控制。这篇技巧解释了如何在一个实例中管理数据的同时提交另一个实例。

前一篇技巧中,我解释了如何创建将请求发送到 Web 服务,然后显示结果的 XForms 表单。这里的不同之处在于,使用这项技术要求您使用符合 Web 服务期望的消息(比如 SOAP 消息)的实例。在本篇技巧中,我将解释如何可以创建另一个实例并与之交互,但是当到达某一时刻时,要提交该 SOAP 格式的实例。

本篇技巧假定您对 XForms 和 Web 服务有基本的了解。本文用到了 Internet Explorer 的 FormsPlayer 插件(请参阅 参考资料 进行下载)。

Web 服务

为了简单起见,我再一次使用普遍存在的天气示例,发送一个 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 表单

首先来创建一个基本的表单。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 元素的值
设置 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 服务请求用作数据实例可能有些麻烦和不便。本篇技巧已经解释了如何创建一个实例用于操作数据,同时创建另一个实例用于发送和接收数据。您将了解:

  1. 创建基本的表单。
  2. 创建两个实例。
  3. 在提交实例之前,将数据从以前的实例迁移到另一个实例中。
  4. 提交请求。
  5. 接收响应。


参考资料



关于作者

Nicholas Chase 是 Studio B的作者,他参与了诸如 Lucent Technologies、Sun Microsystems、Oracle 和 Tampa Bay Buccaneers 等公司的 Web 站点的开发。Nick 曾经是一位高中物理教师、低放射性废弃设备管理员、在线科幻小说杂志的编辑、多媒体工程师和 Oracle 讲师。最近,他成为一家交互式通信公司的首席技术官,该公司位于美国佛罗里达州的克利尔沃特市,而且他还是几本有关 Web 开发的书籍的作者,其中包括 XML Primer Plus (Sams)。他目前正试图购买一个农场,以便与妻子一起饲养羊驼和鸡。他乐于听取读者的意见,您可以通过 nicholas@nicholaschase.com与他联系。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?







回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款