-- 作者:supremeweb
-- 发布时间:5/16/2007 4:25:00 PM
-- 使用 Xforms 创建您自己的数独游戏,第 2 部分: 创建游戏
级别: 中级 [URL=http://www.ibm.com/developerworks/cn/xml/x-xformssudoku2/index.html#author]Nicholas Chase[/URL] ([URL=mailto:ibmquestions@nicholaschase.com?subject=创建游戏&cc=dwxed@us.ibm.com]ibmquestions@nicholaschase.com[/URL]), 自由撰稿人, Backstop Media 2007 年 5 月 14 日 众所周知,数独(Sudoku)正在全球盛行。因为人们可以轻易地在计算机或纸上玩这个数字游戏,再加上使用 XPath 能很容易地在表单中分析数据,所以利用 XForms 创建能玩数独游戏的表单是可行的。[URL=http://www.ibm.com/developerworks/cn/views/xml/articles.jsp?view_by=search&search_by=%E4%BD%BF%E7%94%A8+XForms+%E5%88%9B%E5%BB%BA%E6%82%A8%E8%87%AA%E5%B7%B1%E7%9A%84%E6%95%B0%E7%8B%AC%E6%B8%B8%E6%88%8F]本系列的两篇文章[/URL] 将介绍如何创建游戏客户机,该客户机能向服务器请求开始新游戏,检测合法和非法操作和游戏结束,保存当前游戏状态。同时还将介绍如何为用户生成新游戏。第 2 部分将探究载入和保存游戏。 阅读本文需对 XForms 基础有一定的了解。要复习该内容,请参阅 [URL=http://www.ibm.com/developerworks/cn/xml/x-xformssudoku2/index.html#resources]参考资料[/URL] 部分的链接内容。代码是为 Mozilla Firefox XForms 扩展编写的,并且在该平台上已通过测试,不过其思想适用于任何实现。本文的代码是使用 Mozilla 和 Xforms 扩展编写的,因此要实现本文的代码,需要一个支持 Xforms 的浏览器和一个支持 PHP 的服务器。要生成新的数独迷题,还需要安装 Python 和 Python Sudoku 程序。 Nick Chase 是一名 developerWork 播客 在这个 [URL=http://www.ibm.com/developerworks/blogs/page/scott?entry=twodw_for_february_27_2007&S_TACT=105AGX52&S_CMP=cn-a-x]developerWork 播客[/URL] 中收听作者谈论他所着迷的数独游戏。 回顾 在 [URL=http://www.ibm.com/developerworks/cn/xml/x-xformssudoku2/index.html#part1]第 1 部分[/URL] 中,我们创建了基本的游戏,用户能够使用简单的下拉菜单玩数独游戏。只有当用户成功解答出了迷题时,Submit(提交)按钮才会出现。目前的 Xforms 文档结构如清单 1 所示。 清单 1. 当前页面 <?xml version="1.0"?> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:svg="http://www.w3.org/2000/svg" xmlns:s="http://www.example.com/sudoku" xmlns:b="http://www.example.com/board"> <head> <title>Sudoku</title> <xforms:model> <xforms:instance id="content"> <s:game> <s:row><s:box ro="yes">6</s:box><s:box></s:box> <s:box></s:box><s:box></s:box><s:box></s:box> <s:box ro="yes">9</s:box><s:box></s:box><s:box></s:box> <s:box ro="yes">1</s:box></s:row> ... <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box> <s:box>0</s:box><s:box>0</s:box><s:box>0</s:box><s:box>0 </s:box> <s:box>0</s:box><s:box>0</s:box></s:square> ... <s:submitButtonElement>Submit</s:submitButtonElement> <s:correctRows>no</s:correctRows> </s:game> </xforms:instance> <xforms:bind nodeset="//s:row//s:box[@ro='yes']" readonly="true()" /> <xforms:bind nodeset="//s:submitButtonElement" relevant="/s:game/s:correctRows = 27" /> <xforms:bind nodeset="//s:correctRows" calculate= "count(/s:game/s:row[s:box = '1'][s:box = '2'][s:box = '3'] [s:box = '4'][s:box = '5'][s:box = '6'][s:box = '7'][s:box = '8'] [s:box = '9']) + count(/s:game[s:row[s:box[1]='1']][s:row[s:box[1]='2']] [s:row[s:box[1]='3']][s:row[s:box[1]='4']][s:row[s:box[1]='5']] [s:row[s:box[1]='6']][s:row[s:box[1]='7']][s:row[s:box[1]='8']] [s:row[s:box[1]='9']]) + ... count(/s:game/s:square[s:box = '1'][s:box = '2'] [s:box = '3'][s:box = '4'][s:box = '5'][s:box = '6'] [s:box = '7'][s:box = '8'][s:box = '9'])" /> <xforms:instance id="templates"> <b:template> <b:entry><b:sendvalue>0</b:sendvalue> <b:display></b:display></b:entry> <b:entry><b:sendvalue>1</b:sendvalue> <b:display>1</b:display></b:entry> <b:entry><b:sendvalue>2</b:sendvalue> <b:display>2</b:display></b:entry> ... </b:template> </xforms:instance> <xforms:submission id="submitgame" action="" method="post"/> </xforms:model> <style type="text/css"> div > * {display: inline;} *:read-only { color: red } </style> </head> <body> <img src="images/showlayout.gif" style="float:left;height: 64px; width: 64px;" /> <h1 align="center">Sudoku</h1> <br clear="left" /> <div> <xforms:repeat id="gamerow" nodeset="instance('content')/s:row"> <xforms:repeat id="gamebox" nodeset="s:box"> <span class="test"><xforms:select1 ref="."> <xforms:itemset nodeset="instance('templates')/b:entry"> <xforms:label ref="b:display"/> <xforms:value ref="b:sendvalue"/> </xforms:itemset> </xforms:select1></span> </xforms:repeat> </xforms:repeat> </div> Correct Rows: <xforms:output ref="//s:correctRows" /><br /> <xforms:trigger style="display:block"> <xforms:label>Check it!</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="/s:game/s:square[1]/s:box[1]" value="/s:game/s:row[1]/s:box[1]" /> <xforms:setvalue ref="/s:game/s:square[1]/s:box[2]" value="/s:game/s:row[1]/s:box[2]" /> ... </xforms:action> </xforms:trigger> <xforms:submit ref="/s:game/s:submitButtonElement" submission="submitgame"> <xforms:label>Submit</xforms:label> </xforms:submit> </body> </html> 回顾一下,实例为表格中的每一行都提供了一个 row 元素,另外还包含一个 square 元素用于为计算表格中的 3x3 方块模拟行数据。(要复习规则请参阅 [URL=http://www.ibm.com/developerworks/cn/xml/x-xformssudoku2/index.html#part1]第 1 部分[/URL]。)将 correctRows 元素与一个计算绑定在一起,它可以计算出成功解答出的行数、列数和方格数。当总数达到 27 时 Submit 按钮就会出现。 要创建表格,需要循环遍历每一个 row 元素,通过遍历 templates 实例中的每个 entry 元素为每个 box 元素创建一个下拉列表。如果 box 元素具有一个值,这个值是默认选定的。同样,如果原始实例提供了数值,那么表格上的方框将是只读属性的。 面板如图 1 所示。 图 1. 当前的游戏 现在让我们继续创建数独游戏。 增强界面 玩了一段时间以后,可能会感觉到使用下拉菜单太累了,而直接填入正确的数字会更轻松一点。要达到这个目的,不仅需要重新构造表单,同时还需要避免输入无效值。 先从去除下拉菜单开始(参见清单 2)。 清单 2. 使用文本框替代下拉菜单 ... <xforms:model> <xforms:instance id="content"> <s:game xmlns:s="http://www.example.com/sudoku"> <s:row><s:box s:ro="yes">6</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box s:ro="yes">9</s:box><s:box>.</s:box><s:box>.</s:box> <s:box s:ro="yes">1</s:box></s:row> ... <s:square><s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box><s:box>. </s:box> <s:box>.</s:box><s:box>.</s:box></s:square> ... <s:submitButtonElement>Submit</s:submitButtonElement> <s:correctRows>no</s:correctRows> </s:game> </xforms:instance> ... <style type="text/css"> @namespace xforms url(http://www.w3.org/2002/xforms); div > * {display: inline;} *:read-only { color: red } xforms|input .xf-value, .input-value {width: 30px; background-color: white;} </style> </head> <body> <img src="images/showlayout.gif" style="float:left;height: 64px; width: 64px;" /> <h1 align="center">Sudoku</h1> <br clear="left" /> <div> <xforms:repeat id="gamerow" nodeset="instance('content')/s:row"> <xforms:repeat id="gamebox" nodeset="s:box"> <span> <xforms:input ref="." /> </span> </xforms:repeat> </xforms:repeat> </div> ... 首先注意到代码的底部,select1 元素被一个简单的 input 元素替代了,该元素把 box 元素的内容作为它的值。通常来说,该元素值设定的宽度比我们需要的宽度要宽很多,所以还需使用级联样式表来设置该元素值的宽度。注意,在这之前必须先声明 xforms 的名称空间别名和名称空间。 最后,还要修改现行的数据。之前,我们使用 0 表示用户需要填入的方框,但因为现在是直接在方框中输入当前值(不用像原来一样使用标签),我们把它改成用句点(. )表示,这样也显示地更加清楚。最后显示的结果如图 2 所示。 图 2. 使用文本输入 现在,还有一个问题就是不能防止用户输入无效的值,例如 “42” 或者 “bleh”。幸运的是,我们可以改进一下。 强制限制 Xforms 内建有模式确认(schema validation),因此我们可以轻松地限制用户能输入文本框的值。比如说,我们可以指定输入必须为整数(如清单 3 所示)。 清单 3. 限制输入为整数 ... <xforms:instance id="content"> <s:game xmlns:s="http://www.example.com/sudoku" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <s:row><s:box xsi:type="xsd:int" s:ro="yes">6</s:box><s:box xsi:type="xsd:int" >.</s:box><s:box xsi:type="xsd:int" >.</s:box> <s:box xsi:type="xsd:int" >.</s:box><s:box xsi:type="xsd:int" >.</s:box><s:box xsi:type="xsd:int" s:ro="yes">9</s:box><s:box xsi:type="xsd:int" >.</s:box> <s:box xsi:type="xsd:int" >.</s:box><s:box xsi:type="xsd:int" s:ro="yes">1</s:box></s:row> ... </s:game> </xforms:instance> ... <div> <xforms:repeat id="gamerow" nodeset="instance('content')/s:row"> <xforms:repeat id="gamebox" nodeset="s:box"> <span> <xforms:input ref="."> <xforms:action ev:event="xforms-invalid"> <xforms:setvalue ref=".">.</xforms:setvalue> <xforms:message level="modal">Please choose an integer from 1 to 9.</xforms:message> </xforms:action> </xforms:input> </span> </xforms:repeat> </xforms:repeat> </div> ... 首先,将实例与 XML Schema 名称空间连接起来,并指定 box 元素必须为整数。但是如果表单对不符合类型的数据置之不理的话,这样的指定是没有意义的。 要使表单有所举动,可以指定当输入元素遇到 xforms-invalid 事件时表单采取的动作。当事件发生时,表单将把数值重新设置为句点并显示提示信息。 可以添加一个非整数值测试一下,如图 3 所示。 图 3. 输入无效的值 此时,当您测试时您可能会发现消息框实际上出现了两次。这是因为您把值设置成了非整数,而非整数本身就是无效的输入。 幸运的是,还有另一种选择。我们可以创建一个模式,让它指定所有允许输入的值(如清单 4 所示)。 清单 4. 模式 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/sudoku" xmlns="http://www.example.com/sudoku"> <xsd:element name="game" type="GameType"/> <xsd:element name="row" type="RowType"/> <xsd:element name="square" type="RowType"/> <xsd:element name="box" type="BoxType"/> <xsd:element name="submitButtonElement" type="ButtonType" /> <xsd:element name="correctRows" type="CorrectRowsType" /> <xsd:simpleType name="ButtonType"> <xsd:restriction base="xsd:string" /> </xsd:simpleType> <xsd:simpleType name="CorrectRowsType"> <xsd:restriction base="xsd:int" /> </xsd:simpleType> <xsd:simpleType name='BoxType'> <xsd:restriction base="xsd:string"> <xsd:enumeration value = "."/> <xsd:enumeration value = "1"/> <xsd:enumeration value = "2"/> <xsd:enumeration value = "3"/> <xsd:enumeration value = "4"/> <xsd:enumeration value = "5"/> <xsd:enumeration value = "6"/> <xsd:enumeration value = "7"/> <xsd:enumeration value = "8"/> <xsd:enumeration value = "9"/> </xsd:restriction> </xsd:simpleType> <xsd:complexType name="RowType"> <xsd:sequence> <xsd:element ref="box" minOccurs="9" maxOccurs="9" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="GameType"> <xsd:sequence> <xsd:element ref="row" minOccurs = "9" maxOccurs="9" /> <xsd:element ref="square" minOccurs = "9" maxOccurs="9" /> <xsd:element ref="submitButtonElement" minOccurs="1" maxOccurs="1" /> <xsd:element ref="correctRows" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:schema> 我们明确地指定了 box 元素只能为 1-9 的整数或者为句点。然后把这个模式保存为文件 sudoku.xsd,再从表单中引用它(如清单 5 所示)。 清单 5. 引用模式文件 ... <head> <title>Sudoku</title> <xforms:model schema="./sudoku.xsd"> <xforms:instance id="content"> <s:game xmlns:s="http://www.example.com/sudoku" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <s:row><s:box s:ro="yes">6</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box s:ro="yes">9</s:box><s:box>.</s:box><s:box>.</s:box> <s:box s:ro="yes">1</s:box></s:row> ... 这时再运行表单,我们仍然会看到警示框,不过它只会出现一次,因为根据模式新值是允许输入的。 保存当前游戏 现在已经调整了界面,接下来我们再讨论一下游戏的管理。 第一步是允许用户保存当前游戏。在传统的 HTML 表单中,可以使用复杂的脚本接收数据并保存数据,然后更多的脚本再从中取回。幸运的是,在 Xforms中有更简单的方法 Xforms 允许使用 HTTP 的 “PUT” 方法把实例数据保存到特定的位置。如果 Web 服务器经过正确配置,可以把实例保存在服务器上,但是把数据保存在本地磁盘上是更常用的方法(如清单 6 如示)。 清单 6. 保存到本地文件 ... <xforms:submission id="submitgame" action="" method="post"/> <xforms:submission id="savegame" action="file:///c:/sudoku.txt" replace="instance" instance="content" method="put"/> </xforms:model> ... <xforms:submit ref="/s:game/s:submitButtonElement" submission="submitgame"> <xforms:label>Submit</xforms:label> </xforms:submit> <xforms:submit submission="savegame"> <xforms:label>Save current game</xforms:label> </xforms:submit> </body> </html> 此处我们创建了一个新的 submission 元素,它指定了 content 实例并通知表单使用返回的数据替代实例,而不是页面。然而在本例中,并没有任何返回的数据,因为它还指定了 PUT 方法和存放文件的位置。这样的话当您单击该按钮,它便会把实例数据保存在指定位置下的 XML 文件中。 如果需要保存和载入表单,可以使用这个新按钮(如图 4 所示)。 图 4. 保存按钮 更改一些值并单击 Save(保存)按钮。在 C 盘根目录下将会出现一个 XML 文件,其中包含了刚才保存的实例文档。接下来看看如何将其取回。 载入保存的游戏 一旦我们保存了一个游戏,载入它非常简单。我们要做的就是让表单发送一个 HTTP 请求,然后把数据放入实例中去。这可以通过再创建一个 submission 元素来实现(如清单 7 所示)。 清单 7. 载入数据 ... <xforms:submission id="savegame" action="file:///c:/sudoku.txt" replace="instance" instance="content" method="put"/> <xforms:submission id="loadgame" action="file:///c:/sudoku.txt" replace="instance" instance="content" method="get"/> </xforms:model> <style type="text/css"> ... <xforms:submit submission="savegame"> <xforms:label>Save current game</xforms:label> </xforms:submit> <xforms:submit submission="loadgame"> <xforms:label>Load saved game</xforms:label> </xforms:submit> </body> </html> 在这种情况下,我们通过发送 GET 请求取回数据,浏览器就是使用它请求新 Web 页面的。然后再用取回的数据替代 content 实例中的内容。要查看是否起作用,先保存然后再载入表单,然后改变一些值。保存游戏,然后重新载入表单使游戏回到初始状态。单击 Load saved game(载入保存游戏) 按钮,可以看到我们改变的值又出现了。 提交游戏 现在这个游戏已经非常吸引人了,但不能总是玩这一个游戏吧?当然不会了,我们应该使用户能够向服务器提交当前游戏并获得一个新游戏。稍后您将看到真正的 submission 元素,但是在这之前我们需要调整一下浏览器的设置。 出于安全性考虑,Xforms 只能在最初下载的服务器中载入和保存数据。将表单上传到请求数据的服务器可以解决部分问题。但是问题并没有全部解决。 难点在于事实上我们把数据保存在本地文件中,而不是初始服务器上。要解决这个问题,我们需要在 Xforms 的 “信任服务器” 列表中添加服务器。 为此,选择 Tools->Options 并确保复选框中选择了 “Allow XForms to access other domains”。下一步,单击 Allowed Sites 按钮。添加您所需的服务器名称并选中 Load and Save 复选框。(参见图 5)单击 Add 按钮然后关闭对话框。重启浏览器使修改生效。 图 5. 受信任站点 现在可以开始创建真正的 submission 元素了。从根本上说,我们使用了一个 convertGame.php PHP 脚本用于获得新游戏。稍后我们将看到该脚本。现在还是先更新一下 submission 元素。(如清单 8 所示)。 清单 8. 完整的 submission 元素 ... </xforms:instance> <xforms:submission id="submitgame" action="http://www.backstopmedia.com/sudoku/convertGame.php" replace="instance" instance="content" method="post"/> <xforms:submission id="savegame" action="file:///c:/sudoku.txt" replace="instance" instance="content" method="put"/> ... 和之前一样,我们指定只替代实例而不是整个页面,以及需要替代的实例。同时还添加了将为我们提供新游戏的脚本的 URL。 获取新游戏 除非您是一个数学能手(或者有太多空闲的时间),否则您是不可能独自生成这些迷题的。幸运的是,您也没必要这样做。 Python Sudoku 是一个开放源码的应用程序,能够生成和解答数独迷题。(查看 [URL=http://www.ibm.com/developerworks/cn/xml/x-xformssudoku2/index.html#resources]参考资料[/URL] 获得下载 URL) 它用于生成迷题,可供纸上解答或供其它应用程序使用。不过我们还需要进行一些调整(以及一个支持 Python 脚本的主机)使它能直接向表单输出迷题。 我们将在线下生成许多的迷题,然后随机地把它们返回给表单。要创建这些迷题,解压 Python Sudoku 压缩包并在刚解压的目录下执行如下命令(参见清单 9)。 清单 9. 创建新的迷题 >>>>>python pysdk.py -c game11.sdk Creating sudoku... success! 1 _ _ _ _ _ 5 _ _ _ _ _ 6 _ _ 9 _ _ _ _ _ 3 4 _ _ _ _ _ _ _ _ _ _ _ 1 _ _ 8 _ _ _ 2 _ _ 9 7 9 2 _ _ 5 _ _ _ _ _ 8 _ 3 _ _ 6 _ _ _ _ _ _ _ _ _ _ _ 2 4 1 _ 8 _ 3 _ 在本例中,我们创建了一个 game11.sdk 文件。创建一系列这样的迷题并把它们保存为 game1.sdk、game2.sdk、game3.sdk 等等。 这些文件都使用相同的格式(如清单 10 所示)。 清单 10. 生成的游戏 # boardsize 3 x 3 1 0 0 0 0 0 5 0 0 0 0 0 6 0 0 9 0 0 0 0 0 3 4 0 0 0 0 0 0 0 0 0 0 0 1 0 0 8 0 0 0 2 0 0 9 7 9 2 0 0 5 0 0 0 0 0 8 0 3 0 0 6 0 0 0 0 0 0 0 0 0 0 0 2 4 1 0 8 0 3 0 生成游戏后,把它们移到能执行 PHP 的服务器上面去。这时再创建一个 convertGame.php PHP 脚本,用于随机地选取文件并读取数据,然后创建一个返回给表单的实例。 该脚本如清单 11. 所示。 清单 11. convertGame.php 脚本 <?php $nextGame = rand(1, 10); $lines = file('game'.$nextGame.'.sdk'); echo '<s:game xmlns:s="http://www.example.com/sudoku">'; foreach ($lines as $line_num => $line) { $line = str_replace(" ", "", $line); $line = str_replace("\n", "", $line); if ($line_num > 0 && $line != '') { echo "<s:row>"; for ($x = 0; $x < 9; $x++){ $thisBox = substr($line, $x, 1); if ($thisBox == "0") { echo "<s:box>.</s:box>"; } else { echo "<s:box s:ro='yes'>".$thisBox."</s:box>"; } } echo "</s:row>"; } } echo " <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:square><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box><s:box>.</s:box><s:box>.</s:box> <s:box>.</s:box></s:square> <s:submitButtonElement>Submit</s:submitButtonElement> <s:correctRows>no</s:correctRows>"; echo '</s:game>'; ?> 要开始,需要选择下一个游戏。这里,我们随机地选择 1-10(包含 1 和 10)的整数。然后可以使用这个整数创建用于返回游戏的文件名。然后,使用 file() 函数解压文件中各行中的一组数据。 然后便可以开始输出实例,从根元素 game 打开标记开始。对于每一行,首先解压所有的空格和行末的换行符。完成这步这后,我们能够分辨各行之间的不同,哪些行真正包含了数据而哪些行没有。对这样的每一行,打开一个新的 row 元素然后遍历其中的的每个数字并创建一个 box 元素。如果数字为 0,则把它替换成句点,如果不为 0,则设置为只读属性(ro)。遍历到每一行的末尾,则关闭 row 元素。 如果您是在游戏文件中处理数据,那么将需要一些额外的数据,例如 square 元素、submitButtonElement 元素和 correctRows 元素。最后,关闭 game 元素。 如果您把表单、模式和 convertGame.php 脚本装载在服务器中,并在浏览器中调用它们,可以对其进行测试。(为避免在每次提交之前都必须把迷题解答出来,隐藏在 Submit 按钮之后的 bind 元素被注释掉了。)重复点击 Submit 按钮查看迷题的变化。 就这么简单! 结束语 在 [URL=http://www.ibm.com/developerworks/cn/views/xml/articles.jsp?view_by=search&search_by=%E4%BD%BF%E7%94%A8+XForms+%E5%88%9B%E5%BB%BA%E6%82%A8%E8%87%AA%E5%B7%B1%E7%9A%84%E6%95%B0%E7%8B%AC%E6%B8%B8%E6%88%8F]本系列的两篇文章[/URL] 中,我们创建了一个模拟数独游戏的 Xforms 表单。在 [URL=http://www.ibm.com/developerworks/cn/xml/x-xformssudoku2/index.html#part1]第 1 部分[/URL] 中,我们创建了基本的表单,使用户能够使用下拉菜单玩数独游戏。表单计算迷题是否被解答出来,并根据相应情况做出反应。在第 2 部分中,我们把表单修改成使用文本输入,并且添加了模式约束使用户不能输入无效数据。同时使用户能够在本地保存现有游戏,并能将保存的游戏载入到当前实例。最后,我们探讨了创建新游戏以及如何将它们提供给表单的方法。
|