基础篇:使用XForms控件
XForms 是下一代的基于 Web 的数据处理技术。它用 XML 数据模型和表示元素代替了传统的 HTML 表单。本系列文章有三个部分,介绍了 XForms 及其功能,内容包括基本的 XForms 模型和表单、各种不同类型的控件、基本和高级表单提交技术。本文是此系列文章的第二部分,重点讨论如何使用各种控件创建基于 XForms 的表单以及如何创建数据模型。
简介
XForms 的发展势头迅猛,常见浏览器使用扩展或插件来支持它,此外还有 IBM? Workplace Forms 之类的技术(请参见参考资料部分)。它的灵活和强大对 Web 开发人员很有吸引力,内存占用少和客户端处理又让系统管理员十分感兴趣。W3C 正在审查 XForms 1.1 工作草案文档(1.0 是正式的 Internet 推荐标准,和 XHTML、PNG 以及 CSS 具有同等的地位),IBM 目前带头致力于把那些竞争的基于 XML 的表单标准与 XForms 的特性和功能结合起来。
本文说明了如何使用各种控件创建基于 XForms 的表单、如何建立数据模型以及不同类型的基本提交动作。第 1 部分讨论了各种浏览器以及为了查看和与 XForms 文档交互所需要的插件,本文不再赘述。如果阅读过上一部分,或者已经为使用的浏览器安装了插件,可以直接下载本文中的代码查看示例 XForms。
回页首
创建基本的表单
本系列的第 1 部分中已经创建了一个非常简单的表单,其中包括一个文本输入字段和一个提交按钮,可以向本地主机上假想的搜索引擎发送请求(如图 1 所示)。这类表单仍然很常见,尽管它通常不是孤立在单独的网页上。
图 1. 非常简单的 Web 表单
非常简单的 Web 表单
这是个很好的起点,我们再来看看 XHTML 和 XForms 代码(清单 1)。XForms 的专用代码用粗体字显示,很容易看到,文档的其他部分是纯粹的 XHTML 1.1 Strict。
清单 1. 起点
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
<title>Search Form</title>
<xf:model>
<xf:submission action="http://localhost/imaginary-search-engine"
method="get" id="submit-search"/>
</xf:model>
</head>
<body>
<h1>Search Form</h1>
<p>
Enter a search string, then click the Search button.
</p>
<p>
<xf:input ref="query"><xf:label>Find:</xf:label></xf:input>
<xf:submit
submission="submit-search"><xf:label>Search</xf:label>
</xf:submit>
</p>
</body>
</html>
增加 XForms 名称空间(使用 xf: 前缀)后,已经有了一个 <xf:model> 块,它声明了名为 submit-search 的提交动作,可以使用标准的 HTTP GET 方法提交指定的搜索字符串。<body>, <xf:input> 和 <xf:submit> 元素中的内容构成了简单的表单,包括输入字段和提交按钮,后者触发 <xf:model> 中声明的动作。
如果愿意的话,可以直接试一试,<xf:input> 和 <xf:submit> 元素的距离、先后或位置没有任何特殊要求,它们可以出现在文档 <body> 的任何地方。表单的输入部件表示与其数据模型分离开来。
由于将使用该文档作为本文中其他 XForms 文档的出发点,这里还提供了 XMLSchema 和 xml-events 的 XML 名称空间声明,XForms 利用这两个辅助标准分别提供标准数据类型和表单事件。
回页首
创建一个简单的模型
XForms 的吸引人的原因之一是其将数据模型从表示中分离出来的方法。再看看清单 1,模型(<xf:model> 块中)本身存在于 XHTML 文档的 <head> 中。
当然,除了一个提交动作之外这个模型完全是空的。它不含任何数据!
不过,先别忙。系统(在这里就是支持 XForms 的浏览器)为您创建了一个(如清单 2 所示),其中包含表单引用的数据字段。
清单 2. 简单表单默认的完整 <xf:model>
<xf:model>
<xf:instance>
<data xmlns="">
<query/>
</data>
</xf:instance>
<xf:submission action="http://localhost/imaginary-search-engine"
method="get" id="submit-search"/>
</xf:model>
显式地包含这种形式的实例为表单额外增加了一层验证;表单控件(比如这个简单表单中的文本字段和提交按钮)所引用的字段必须存在于模型实例之中。引用不存在的实例元素的控件要么不能呈现,要么生成错误消息(取决于 XForms 实现)。
回页首
默认值
如果显式地声明数据实例,可用它来定义默认值,只要将默认值放在字段元素中即可。清单 3 中的模型和清单 2 相同,只不过为查询提供了一个有帮助的默认值(如图 2 所示)。
清单 3. 在 <xf:instance> 中直接包含默认值
<xf:model>
<xf:instance>
<data xmlns="">
<query>One or more search keywords.</query>
</data>
</xf:instance>
<xf:submission action="http://localhost/imaginary-search-engine"
method="get" id="submit-search"/>
</xf:model>
图 2. 在模型实例中包含帮助性的提示或者有意义的默认值
在模型实例中包含帮助性的提示或者有意义的默认值
回页首
隐藏值和隐藏控件
用户触发提交动作时,XForms 发送完整的 XML 文档(数据模型实例)。创建模型实例时可以包含需要的任何数据。
因而不再需要在表单中使用隐藏控件。如果有些数据需要发送到服务器上的表单处理程序,但是又不必显示给用户(或者需要保持不变),那么可以将其添加到模型实例中(如清单 4 所示)。
清单 4. 在实例而不是表单中包含隐藏数据或者常量
<xf:model>
<xf:instance>
<data xmlns="">
<query>One or more search keywords.</query>
<engine-version>2</engine-version>
<results>25</results>
</data>
</xf:instance>
<xf:submission action="http://localhost/imaginary-search-engine"
method="get" id="submit-search"/>
</xf:model>
该例中,<engine-version> 和 <results> 永远不会被表单控件引用,也不会被用户看到(除非用户查看源代码)。这些数据组作为查询的一部分发送给 imaginary-search-engine,imaginary-search-engine 可以利用它们选择搜索引擎和设置返回的结果数。
回页首
加载实例
如果数据模型很大,或者需要向用户隐藏某些数据,可以从外部 XML 文件加载实例(如清单 5 所示)。
清单 5. XML 文件中的简单模型实例
<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="">
<query>One or more search keywords.</query>
<engine-version>2</engine-version>
<results>25</results>
</data>
只要让 <xf:instance> 引用具体的实例 URL(如清单 6 所示)就可以了。
清单 6. 引用外部模型实例
<xf:model>
<xf:instance src="search-instance.xml"/>
<xf:submission action="http://localhost/imaginary-search-engine"
method="get" id="submit-search"/>
</xf:model>
由于 <xf:instance> 的 src 属性可以从任何 URL 加载 XML 数据,可以用 XForms 编辑或原样表示任何数据。多数 XForms 实现都要求源文档的 URL 在同一个域中,但部分 XForms 实现也允许您配置一个可信任的站点列表。
回页首
XML 数据中的引用
加载 XML 文件作为数据实例时,有可能无法控制 XML;数据也许是数据库或者其他某个应用程序提供的。如何引用 XML 中的某个元素呢?到目前为止,您还只看到了引用与数据模型匹配的元素。
XForms 表单元素使用的数据模型引用实际上是 XPath 表达式,因此可用 XPath 表达式来引用模型中的任何元素。清单 7 显示了一个扩展后的实例,其中包括一些嵌套元素。
清单 7. 更复杂的数据模型实例
<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="">
<query>One or more search keywords.</query>
<engine-version>2</engine-version>
<results>25</results>
<some>
<additional>
<info status="important">Nested info.</info>
</additional>
</some>
</data>
可用 XPath 表达式 some/additional/info(或者 /data/some/additional/info,如果使用绝对路径的话)来访问 <info> 元素,或者用 some/additional/info/@status 访问 <info> 元素的 status 属性。清单 8 显示了可用于编辑该数据文件的表单,在这里假设 Web 服务器支持 PUT 方法(可能需要某种身份验证来保护这种功能)。
清单 8. 编辑更复杂的 XML 数据
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms">
<head>
<title>Search Form</title>
<xf:model>
<xf:instance src="http://localhost/~chrish/data.xml"/>
<xf:submission action="http://localhost/~chrish/data.xml"
method="put" id="submit-edit"/>
</xf:model>
</head>
<body>
<h1>XPath</h1>
<p>
Change the info and status!
</p>
<p>
<xf:input ref="some/additional/info"><xf:label>New
info:</xf:label></xf:input><br/>
<xf:input ref="some/additional/info/@status"><xf:label>New
status:</xf:label></xf:input>
<xf:submit
submission="submit-edit"><xf:label>Save</xf:label></xf:submit>
</p>
</body>
</html>
无论在客户机还是服务器上,对 XForms 来说 XPath 都是一种很好的辅助技术;一旦掌握了 XPath,就可以在表单和表单处理程序中使用它。
回页首
控件的类型
到目前为止,我们只用到了 <xf:input> 和 <xf:submit> 控件,但是 XForms 还提供了很多其他的表单控件。我们来看看这些控件及其在 HTML 中的等价物。
<xf:group>(HTML <fieldset>)用于对表单中的控件进行逻辑分组。清单 9 说明了如何使用 <xf:group> 为三个输入字段加标签。
清单 9. 分组控件
<xf:group>
<xf:label>Personal Information</xf:label>
<p><xf:input ref="lastname"><xf:label>Last
name:</xf:label></xf:input></p>
<p><xf:input ref="firstname"><xf:label>First
name:</xf:label></xf:input></p>
<p><xf:input
ref="address"><xf:label>Address:</xf:label></xf:input></p>
</xf:group>
<xf:input>(HTML <input type="text">)显示一个标准的文本输入字段,我们已经多次用到了它。
<xf:secret>(HTML <input type="password">)显示一个文本输入字段,输入的内容隐藏起来,适用于输入口令或者其他保密数据。<xf:secret> 与文档源代码中的 <xf:input> 完全相同。
<xf:select appearance="full">(HTML <input type="checkbox">)为用户提供一个或多个可选项,允许多选。清单 10 给出了一个例子。
清单 10. 多选控件
<xf:select ref="potato-chips" appearance="full">
<xf:label>Favourite flavours:</xf:label>
<xf:item><xf:label>Dill
Pickle</xf:label><xf:value>dill</xf:value></xf:item>
<xf:item><xf:label>Ketchup</xf:label><xf:value>ketchup<
/xf:value></xf:item>
<xf:item><xf:label>Plain</xf:label><xf:value>plain<
/xf:value></xf:item>
<xf:item><xf:label>Salt &
Vinegar</xf:label><xf:value>snv</xf:value></xf:item>
</xf:select>
<xf:select appearance="minimal">(HTML <select multiple>)用于从菜单或列表中选择一个或多个项,对 appearance 属性使用 minimal 可以在更小的区域中呈现项目列表。
<xf:select1>(HTML <input type="radio">)类似于 <xf:select>,但是只允许用户从列表中选择一项。它可以呈现为一组单选按钮、可滚动的选择区域或者菜单,使用 appearance 属性告诉呈现引擎应该呈现为什么。
<xf:select1> 和嵌套的 <xf:choices>(HTML <select> 和嵌套的 <optgroup>)允许用户从分组列表中选择一项。<xf:choices> 子列表的标签呈现在列表中,但是不能选择。清单 11 显示了一个饮料列表让用户选择,用户也可以从非酒精和酒精饮料中选择。
清单 11. 从多个分组中选择一项
<xf:select1 ref="drink">
<xf:label>Drink:</xf:label>
<xf:item><xf:label>None</xf:label><xf:value>none
</xf:value></xf:item>
<xf:choices>
<xf:label>Soft drinks</xf:label>
<xf:item><xf:label>Juice</xf:label><xf:value>juice
</xf:value></xf:item>
<xf:item><xf:label>Milk</xf:label><xf:value>milk
</xf:value></xf:item>
<xf:item><xf:label>Soda</xf:label><xf:value>soda
</xf:value></xf:item>
<xf:item><xf:label>Water</xf:label><xf:value>water<
/xf:value></xf:item>
</xf:choices>
<xf:choices>
<xf:label>Wine and beer</xf:label>
<xf:item><xf:label>Beer</xf:label><xf:value>beer<
/xf:value></xf:item>
<xf:item><xf:label>Red
wine</xf:label><xf:value>redwine</xf:value></xf:item>
<xf:item><xf:label>White
wine</xf:label><xf:value>whitewine</xf:value></xf:item>
</xf:choices>
</xf:select1>
<xf:textarea>(HTML <textarea>)显示一个多行文本输入字段,如果默认值不合适可使用 CSS 样式控制区域的大小。
<xf:trigger>(HTML <input type="button">)呈现一个动作按钮。按钮没有预定义的行为,因此需要为其附加一个动作,按钮被激活时将触发该动作。清单 12 中的 <xf:trigger> 激活一个 JavaScript? 函数,名为 calculate()。
清单 12. 调用 JavaScript 函数 calculate() 的按钮
<xf:trigger>
<xf:label>Calculate</xf:label>
<script ev:event="DOMActivate" type="text/javascript">
calculate();
</script>
</xf:trigger>
要注意,这里第一次使用 ev: 名称空间,虽然在前面的基本表单的示例中早已声明。它用于引用标准 XML Events 属性 ev:event,它告诉触发器什么时候激活脚本。
<xf:trigger>(HTML <input type="image">)也可用于为表单添加图像按钮,只需在 <xf:label> 元素中插入 <img> 元素或者使用 CSS 将图像作为元素的背景即可。
如果正在把某些 HTML 表单升级到 XForms 表单,可以使用 <xf:trigger>(HTML <input type="reset">)增加 Reset 按钮(升级规范可能要求“全部功能”,包括无用的 Reset 按钮)。清单 13 说明了如何创建一个表单复位按钮,但是不要在新表单中使用它:最终用户永远不会有意识地单击 Reset 按钮。
清单 13. 实现无用的历史遗留物:Reset 按钮
<xf:trigger>
<xf:label>Reset</xf:label>
<xf:reset ev:event="DOMActivate"/>
</xf:trigger>
<xf:upload>(HTML <intput type="file">)用于实现文件上传。和其他控件相比这个更复杂一点,因为它需要一种特殊的 <xf:submission> 方法:form-data-post(如清单 14 所示)。
清单 14. 使用 <xf:submission> 方法上传文件
<xf:model>
...
<xf:submission action="http://localhost/upload-engine"
method="form-data-post" id="upload"/>
</xf:model>
表单下方的 <xf:upload> 元素看起来类似于 <xf:submit> 或 <xf:input>(如清单 15 所示)。
清单 15. 使用 <xf:upload> 上传文件
<xf:upload ref="upload"><xf:label>Upload a
file:</xf:label></xf:upload>
另外,还有一些 HTML 中不存在的控件。
<xf:output> 允许在文档中增加一些文本值。比如清单 7 中向数据模型增加了 <results> 元素。虽然用户不能修改它,但是可以通过编辑模型来改变它(特别是如果使用外部 XML 文件中定义的模型的话)。可以使用 <xf:output> 元素向用户显示这些信息(如清单 16 所示)。
清单 16. 使用 <xf:output> 显示模型中的数据
<p>
Your search will return a maximum of
<xf:output ref="results"> matches.
</p>
<xf:range> 为用户显示一个范围选择条(slide)或者适合于获得受约束值的其他控件。比方说,可以用三个 range 让用户输入红/绿/蓝中的一个作为突出显示搜索结果的颜色(如清单 17 所示)。
清单 17. 使用范围输入控件
<p>
Keyword highlight:<br/>
<xf:range ref="r" start="0" end="100" step="1"><xf:label>Red</xf:label></xf:range><br/>
<xf:range ref="g" start="0" end="100" step="1"><xf:label>Green</xf:label></xf:range><br/>
<xf:range ref="b" start="0" end="100" step="1"><xf:label>Blue</xf:label></xf:range>
</p>
现在介绍了各种 XForms 输入控件(和一个输出控件),下面来看看各种不同的提交动作。
回页首
基本提交动作
XForms 标准支持通常的 HTML 表单提交方法,但是 HTML 需要 method 和 enctype 来指定提交方法,而 XForms 只需要一个 method。
<xf:submission method="form-data-post" action="url"/> 和 HTML 中的 <form method="post" enctype="multipart/form-data"> 相同,可以按同样的方法在收到 URL 时被处理。
<xf:submission method="get" action="url"/> 和 HTML 中的 <form method="get"> 相同。
<xf:submission method="urlencoded-post" action="url"> 和 HTML 中的 <form method="post" enctype="application/x-www-form-urlencoded"> 相同。
除了和 HTML 兼容的提交方法之外,XForms 还定义了两种新的提交动作,method="post" 和 method="put"。
method="post" 动作将表单数据模型实例作为 XML 文档 post 给接收 URL,适用于 XSLT 或者其他 XML 处理技术。客户机不需要制定编码或者转义,服务器上也不需要特殊处理(除了标准 XML 解析以外)。
method="put" 动作将表单数据模型实例作为 XML 文档 put 给目标 URL。如果服务器支持 PUT 方法,并且允许对目标 URL 使用该方法,该 XML 文档将代替目标 URL 上的文件。可利用该方法现场编辑“任何”XML 文档,只需要通过和后来 put 动作要用到的相同的 URL 加载数据模型实例即可。
纯 XML post 和 put 方法是 XForms 目标的一部分,为数据处理带来了一定程度的灵活性。
回页首
结束语
XForms 提供了一致的、清晰的基于 XML 的数据模型,可以在文档或者页面处理期间加载的外部文件中直接包含任意的 XML。该标准支持现在所有 HTML 表单控件的等价物,并增加了另外两个有用的控件用于范围选择和显示数据。基本 XForms 提交动作包含了原来的 HTML 的提交方法,并增加了两种基于 XML 的方法。本文全面介绍了这些控件,您可以以此为基础开始自己的 XForms 体验。
XForms 学习交流群:38587873/. 欢迎大家入群讨论。