创建基本的表单
本系列的第 1 部分中已经创建了一个非常简单的表单,其中包括一个文本输入字段和一个提交按钮,可以向本地主机上假想的搜索引擎发送请求(如图 1 所示)。这类表单仍然很常见,尽管它通常不是孤立在单独的网页上。
图 1. 非常简单的 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 目标的一部分,为数据处理带来了一定程度的灵活性。