以文本方式查看主题

-  W3CHINA.ORG讨论区 - 语义网·描述逻辑·本体·RDF·OWL  (http://bbs.xml.org.cn/index.asp)
--  『 HTML/XHTML/Ajax/Web 2.0/Web 3.0 』  (http://bbs.xml.org.cn/list.asp?boardid=22)
----  使用 Xforms 创建您自己的数独游戏,第 2 部分: 创建游戏  (http://bbs.xml.org.cn/dispbbs.asp?boardid=22&rootid=&id=46978)


--  作者: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 部分中,我们把表单修改成使用文本输入,并且添加了模式约束使用户不能输入无效数据。同时使用户能够在本地保存现有游戏,并能将保存的游戏载入到当前实例。最后,我们探讨了创建新游戏以及如何将它们提供给表单的方法。


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
7,640.625ms