基于Curl的RIA系统开发入门
作者:解秋生
本文将先对Curl语言的基础作一个简单的介绍,然后再阐述怎样用Curl语言开发当今世界上盛行的RIA系统。
1.简介
Curl是一种新型的计算机语言,它的技术渊源于麻省理工学院(MIT)的某工程项目(1995)。用Curl开发的程序要通过网络浏览器来执行 ,即所谓的客户端语言。用浏览器执行Curl程序的前提条件是在客户端事先安装Curl的执行环境,即Surge RTE插件。此插件可从[url]www.curl.com[/url]、 [url]www.curlap.com[/url] 下载。 Curl语言为开发匹敌于传统的单机界面以及客户端/服务器界面等的应用程序提供了一个良好的开发平台。
2.Curl语言的基础
2.1 关于开发
Curl语言有开发应用程序的统一开发环境(IDE)。IDE具有可视化编程功能, 可进行画面布局设计、控件配置和事件任务编辑的开发。此外,Curl语言还提供用Curl语言自身编制的在线辅助文档。文档采用超文本标记方式,不仅有API的说明,还有立即可以取用的例题。更有甚的是,那些例题都可以当场进行修改和执行调试 ,这大大方便了对Curl功能的调查工作。当然,不用Curl的IDE,而用自己惯用的文本编辑器(加以适当的配置)也可以开发Curl应用程序。
2.2 Cur语言之基础中的基础
Curl语言具有丰富的表现能力,在这里就其基础中的基础加以说明。
2.2.1代码块
Curl程序是由大括号“{”和“}”括起的代码块组成。代码块可以嵌套。 比方说,Curl小应用程序的文本宣言要用 {curl 6.0 applet} 代码块表示。
2.2.2 小应用程序(Applet)
用Curl开发的程序是以Applet为单位处理的。应用程序既可以由一个Applet组成,又可以 由多个Applet组成。当然,用子Applet组成的情况也有。父applet和子applet之间可以互相通信。一般来说,Applet由文本宣言、附加信息以及代码主体组成。 比方说,如想编制一个显示「Hello World!」的小应用程序,那么应像List 1那样编辑。
List 1 Curl版Hello World!
{curl 6.0 applet}
{curl-file-attributes character-encoding = “utf-8”}
Hello World!
这里,第1行是文本宣言,第2行是附加信息,第3行是代码主体。
2.2.3 注释
Curl用|| 和 |# to be commented #|对程序进行注释。将||置于某一行的某处,那么那一行的||之后就变成注释 ,而|# #|则用来进行复数行加注。
2.2.4 富文本
Curl具有超文本标记语言的功能 ,同时还备有丰富的文本格式化函数。比方说, 如想对字符串加粗,那么调用bold函数即可。 即{bold 字符串}。此外还有诸如big、small、italic等函数。有趣的是函数可以嵌套调用。例如,{big {big 字符串}}将对指定字符串进行两次big 处理。在表达文章时,经常使用的文本函数有pre, paragraph以及text等。以text 为例,如在调用时指定color、font-size、 font-style、font-family、font-weight等关键字参数,那么可以实现多种不同的文字样式。
2.2.5 流程控制
Curl的流程控制有 {if …}、{if …else …}、{if … elseif …else …}、{while …}、{until …}、{switch …case…else…}以及{type-switch…case…else…}。Type-switch是在判断变量类型的时候使用的。Switch的case语句的常量表达式可以用多个数值。例如可以表现为 case “1”, “2”, “4” do。 2.2.6 字符串
字符串有可变的类 StringBuf 和不可变的类String。StringBuf使用concat方法可以和其他字符串进行连接。这个类可以使用检索 find、比较compare、空白删除 trim、部分字符串substr等方法。使用&连接多个变量或者定量生成新的String。例如{let str:String=”123” & 1 & str-x}。关于字符串和数字之间的转换 :将字符串转换成数字时使用字符串的to-int、to-double;数字转换成字符串时使用(1){format “%d”, int-var};(2){String int-var};(3) “” & int-var。
2.2.7 容器
Curl的容器有{Array-of type}、{Set-of type}、{HashTable-of type1, type2}及{Array-2-of type},这里的type可以是原始变量也可以是类。
2.2.8 类定义
Curl的类是由{define-class [访问类型] [修饰子] 类名 [{inherits 父类}]
[类变量]
[类过程]
域
构造函数
Setter
Getter
选项
方法
}
的形式来定义的,下面是一个简单的类构造的例子。
{define-class public MyName
field public last-name:String=””
field public first-name:String=””
}
2.2.9 函数定义
函数由以下语法定义:
{define-proc public {my-proc-name x1:String, x2:String, y:String=”x”, …}:(String, String)
{if y==”x” then let x3:String = x1 & “, “ & x2}
{return x2, x1}
}
Curl程序有3种参数。即:位置参数 (x1和x2)、关键词参数(y)以及剩余参数(…)。位置参数在引用时必须指定;关键词参数在引用时可以省略;剩余参数在引用时可以指定为任意数。Curl可以返回多个值。类的构造函数(constructor)、设计(factory)以及方法(method)等都使用同样的参数形式。 因此,Curl的类和函数的表达能力极具柔软性和扩张性。 2.2.10 布局
Curl的布局控件有 Canvas、OverlayBox以及 Hbox、VBox。前者可以通过2个坐标来定位,后者只是嵌套。但是,即使是只用Box系列和Frame (Frame、ScrollBox)的嵌套组合也能作出很不错的应用程序。
2.2.11 文档样式
Curl有3种文档样式。 (1)DefaultDocumentToc为默认的样式,根据内容的多少会自动对滚动轴进行调节。 (2) TocDocument将在页面左侧自动生成目录。 (3)PlainDocument是在图表表示范围内根据窗口的大小自动收缩或扩张图表。如果要充分发挥Curl的弹×××,最好是选用样式(3)。文档样式定义写在应用程序之起始程序的文本宣言之下,第一个程序块之上。其语句形式为{document-style PlainDocument}。
2.2.12 持久化数据
Curl可以处理Http Cookies。特别是可以共享IE浏览器的 Cookies。所以,Curl可以对IE的Cookies进行读写。除了Cookies以外,Curl有独自的持久化数据功能。使用持久化数据可以在本地系统存取数据。持久化数据被存在本地系统的<user-name>\curl-client-data\persistent-storage目录下。文件名是自动生成的。可以持久化的数据类型包括基本类型、数量、字符串、哈希表、日期等等,List 2例示了日期的读入读出。其处理顺序为:首先应用程序(applet)之起始程序的文本宣言之下定义Repository;然后在任意地方使用{get-persistent-data <key>}读取持久化数据,使用{set-persistent-data <key>, <value>}和{commit-persistent-data}保存持久化数据。
使用持久化数据可以在本地保存上一次启动程序时所产生的数据或结束时的状态,这样,下次启动以后可以再次读入数据,进行处理,从而再现上次的状态。持久化数据也可以解决多个应用程序(applet)之间的数据共享问题。
List 2
{curl 3.0 applet}
{persistent-data
“Data storage”,
duration = 180days,
max-size = 1024
}
{value
let x:#String
{try
set x = {get-persistent-data “visit date”}
catch e:KeyNotFoundException do
set x = “你是初次访问。“
}
{set-persistent-data “visit date”, {{DateTime}.to-String}}
{commit-persistent-data}
{text The last time you visited this site was: {value x}}
}
2.2.13 数量和单位
Curl可以表示将数值和测量单位连成一体的数量型数据。比如说3cm、0.7gram以及2(m/s^2)这样的数据。编译器可以分辨这样的数量数据并进行处理。比如说可以进行这样的运算 3cm + 10m。通过使用数量型数据,不仅使得代码变得容易读懂,而且,使得打印表格时的位置调整及尺寸指定也变得更加容易。
2.2.14 打印
Curl提供打印用的函数{print-graphic <g>}。这个函数可以指定页面的单复,标题,页数,打印日期,伸缩等功能,对报表的设计和打印有很大作用。
2.2.15 文件的输入输出
Curl有远程和本地两种文件路径机能。可以使用File和Directory类的方法对文件夹和文件的属性进行操作以及输入和输出。另外,通过read-open和write-open函数和TextInputStream/TextOutputStream等类的相配合也可以进行文件输入和输出。文件的读取除了通常的同期读取以外还有非同期读取。值得注意的是,访问本地文件要受安全性制约的限制。
2.2.16 其它
Curl提供了丰富的表现手段和细致的API,这里介绍的只是基础中的基础,冰山上的一角。详细的内容请参考在线文档和参考文献中的资料。
这里补充一下,Curl的变量声明要使用{let var1:int=1, var2:double=1.2},变量代入要使用{set var1=2, var2=2.4}。let和set可以对复数个变量进行操作。还有,Curl没有像Java/C/C++/C#的int-var++表现形式,取而代之的有{inc int-var}{dec int-var}。当然,下面这样的表现形式也可以:{set int-var=int-var + 1}。
3.与服务器端的联动 3.1 系统构成概念Curl是客户端语言,构建Web应用程序时有必要和服务器端进行联动。图1是系统构成的概念。
Curl和服务器端的通信使用http/https协议。对Web服务器没有特别的要求,可以和现有的服务器技术通用。比如说IIS/ASP/ASP.NET和Apache+Tomcat/JSP+Servlet等组合来构建系统。至于,服务器端语言,PHP、Perl、CGI以及Coldfusion都可以使用。通信方法可以使用get和post。一般来说,查询数据使用get(上传量少),上传数据使用post。
下面以从数据库取得数据为例进行说明:
① Curl向相应的服务器端程序发出http请求;
② 服务器端程序根据请求从中抽取参数,组装好SQL命令后,向数据库发出SQL命令;
③ 服务器端程序对取出的数据进行加工,以一定的格式 (XML、CSV等)返回给Curl;
④ Curl取得服务器端传来的数据,进行处理后,以图形、表格或者富文本等形式将结果传送到浏览器。
2.1 关于开发
Curl语言有开发应用程序的统一开发环境(IDE)。IDE具有可视化编程功能, 可进行画面布局设计、控件配置和事件任务编辑的开发。此外,Curl语言还提供用Curl语言自身编制的在线辅助文档。文档采用超文本标记方式,不仅有API的说明,还有立即可以取用的例题。更有甚的是,那些例题都可以当场进行修改和执行调试 ,这大大方便了对Curl功能的调查工作。当然,不用Curl的IDE,而用自己惯用的文本编辑器(加以适当的配置)也可以开发Curl应用程序。
2.2 Cur语言之基础中的基础
Curl语言具有丰富的表现能力,在这里就其基础中的基础加以说明。
2.2.1代码块
Curl程序是由大括号“{”和“}”括起的代码块组成。代码块可以嵌套。 比方说,Curl小应用程序的文本宣言要用 {curl 6.0 applet} 代码块表示。
2.2.2 小应用程序(Applet)
用Curl开发的程序是以Applet为单位处理的。应用程序既可以由一个Applet组成,又可以 由多个Applet组成。当然,用子Applet组成的情况也有。父applet和子applet之间可以互相通信。一般来说,Applet由文本宣言、附加信息以及代码主体组成。 比方说,如想编制一个显示「Hello World!」的小应用程序,那么应像List 1那样编辑。
List 1 Curl版Hello World!
{curl 6.0 applet}
{curl-file-attributes character-encoding = “utf-8”}
Hello World!
这里,第1行是文本宣言,第2行是附加信息,第3行是代码主体。
2.2.3 注释
Curl用|| 和 |# to be commented #|对程序进行注释。将||置于某一行的某处,那么那一行的||之后就变成注释 ,而|# #|则用来进行复数行加注。
2.2.4 富文本
Curl具有超文本标记语言的功能 ,同时还备有丰富的文本格式化函数。比方说, 如想对字符串加粗,那么调用bold函数即可。 即{bold 字符串}。此外还有诸如big、small、italic等函数。有趣的是函数可以嵌套调用。例如,{big {big 字符串}}将对指定字符串进行两次big 处理。在表达文章时,经常使用的文本函数有pre, paragraph以及text等。以text 为例,如在调用时指定color、font-size、 font-style、font-family、font-weight等关键字参数,那么可以实现多种不同的文字样式。
2.2.5 流程控制
Curl的流程控制有 {if …}、{if …else …}、{if … elseif …else …}、{while …}、{until …}、{switch …case…else…}以及{type-switch…case…else…}。Type-switch是在判断变量类型的时候使用的。Switch的case语句的常量表达式可以用多个数值。例如可以表现为 case “1”, “2”, “4” do。 2.2.6 字符串
字符串有可变的类 StringBuf 和不可变的类String。StringBuf使用concat方法可以和其他字符串进行连接。这个类可以使用检索 find、比较compare、空白删除 trim、部分字符串substr等方法。使用&连接多个变量或者定量生成新的String。例如{let str:String=”123” & 1 & str-x}。关于字符串和数字之间的转换 :将字符串转换成数字时使用字符串的to-int、to-double;数字转换成字符串时使用(1){format “%d”, int-var};(2){String int-var};(3) “” & int-var。
2.2.7 容器
Curl的容器有{Array-of type}、{Set-of type}、{HashTable-of type1, type2}及{Array-2-of type},这里的type可以是原始变量也可以是类。
2.2.8 类定义
Curl的类是由{define-class [访问类型] [修饰子] 类名 [{inherits 父类}]
[类变量]
[类过程]
域
构造函数
Setter
Getter
选项
方法
}
的形式来定义的,下面是一个简单的类构造的例子。
{define-class public MyName
field public last-name:String=””
field public first-name:String=””
}
2.2.9 函数定义
函数由以下语法定义:
{define-proc public {my-proc-name x1:String, x2:String, y:String=”x”, …}:(String, String)
{if y==”x” then let x3:String = x1 & “, “ & x2}
{return x2, x1}
}
Curl程序有3种参数。即:位置参数 (x1和x2)、关键词参数(y)以及剩余参数(…)。位置参数在引用时必须指定;关键词参数在引用时可以省略;剩余参数在引用时可以指定为任意数。Curl可以返回多个值。类的构造函数(constructor)、设计(factory)以及方法(method)等都使用同样的参数形式。 因此,Curl的类和函数的表达能力极具柔软性和扩张性。 2.2.10 布局
Curl的布局控件有 Canvas、OverlayBox以及 Hbox、VBox。前者可以通过2个坐标来定位,后者只是嵌套。但是,即使是只用Box系列和Frame (Frame、ScrollBox)的嵌套组合也能作出很不错的应用程序。
2.2.11 文档样式
Curl有3种文档样式。 (1)DefaultDocumentToc为默认的样式,根据内容的多少会自动对滚动轴进行调节。 (2) TocDocument将在页面左侧自动生成目录。 (3)PlainDocument是在图表表示范围内根据窗口的大小自动收缩或扩张图表。如果要充分发挥Curl的弹×××,最好是选用样式(3)。文档样式定义写在应用程序之起始程序的文本宣言之下,第一个程序块之上。其语句形式为{document-style PlainDocument}。
2.2.12 持久化数据
Curl可以处理Http Cookies。特别是可以共享IE浏览器的 Cookies。所以,Curl可以对IE的Cookies进行读写。除了Cookies以外,Curl有独自的持久化数据功能。使用持久化数据可以在本地系统存取数据。持久化数据被存在本地系统的<user-name>\curl-client-data\persistent-storage目录下。文件名是自动生成的。可以持久化的数据类型包括基本类型、数量、字符串、哈希表、日期等等,List 2例示了日期的读入读出。其处理顺序为:首先应用程序(applet)之起始程序的文本宣言之下定义Repository;然后在任意地方使用{get-persistent-data <key>}读取持久化数据,使用{set-persistent-data <key>, <value>}和{commit-persistent-data}保存持久化数据。
使用持久化数据可以在本地保存上一次启动程序时所产生的数据或结束时的状态,这样,下次启动以后可以再次读入数据,进行处理,从而再现上次的状态。持久化数据也可以解决多个应用程序(applet)之间的数据共享问题。
List 2
{curl 3.0 applet}
{persistent-data
“Data storage”,
duration = 180days,
max-size = 1024
}
{value
let x:#String
{try
set x = {get-persistent-data “visit date”}
catch e:KeyNotFoundException do
set x = “你是初次访问。“
}
{set-persistent-data “visit date”, {{DateTime}.to-String}}
{commit-persistent-data}
{text The last time you visited this site was: {value x}}
}
2.2.13 数量和单位
Curl可以表示将数值和测量单位连成一体的数量型数据。比如说3cm、0.7gram以及2(m/s^2)这样的数据。编译器可以分辨这样的数量数据并进行处理。比如说可以进行这样的运算 3cm + 10m。通过使用数量型数据,不仅使得代码变得容易读懂,而且,使得打印表格时的位置调整及尺寸指定也变得更加容易。
2.2.14 打印
Curl提供打印用的函数{print-graphic <g>}。这个函数可以指定页面的单复,标题,页数,打印日期,伸缩等功能,对报表的设计和打印有很大作用。
2.2.15 文件的输入输出
Curl有远程和本地两种文件路径机能。可以使用File和Directory类的方法对文件夹和文件的属性进行操作以及输入和输出。另外,通过read-open和write-open函数和TextInputStream/TextOutputStream等类的相配合也可以进行文件输入和输出。文件的读取除了通常的同期读取以外还有非同期读取。值得注意的是,访问本地文件要受安全性制约的限制。
2.2.16 其它
Curl提供了丰富的表现手段和细致的API,这里介绍的只是基础中的基础,冰山上的一角。详细的内容请参考在线文档和参考文献中的资料。
这里补充一下,Curl的变量声明要使用{let var1:int=1, var2:double=1.2},变量代入要使用{set var1=2, var2=2.4}。let和set可以对复数个变量进行操作。还有,Curl没有像Java/C/C++/C#的int-var++表现形式,取而代之的有{inc int-var}{dec int-var}。当然,下面这样的表现形式也可以:{set int-var=int-var + 1}。
3.与服务器端的联动 3.1 系统构成概念Curl是客户端语言,构建Web应用程序时有必要和服务器端进行联动。图1是系统构成的概念。
Curl和服务器端的通信使用http/https协议。对Web服务器没有特别的要求,可以和现有的服务器技术通用。比如说IIS/ASP/ASP.NET和Apache+Tomcat/JSP+Servlet等组合来构建系统。至于,服务器端语言,PHP、Perl、CGI以及Coldfusion都可以使用。通信方法可以使用get和post。一般来说,查询数据使用get(上传量少),上传数据使用post。
下面以从数据库取得数据为例进行说明:
① Curl向相应的服务器端程序发出http请求;
② 服务器端程序根据请求从中抽取参数,组装好SQL命令后,向数据库发出SQL命令;
③ 服务器端程序对取出的数据进行加工,以一定的格式 (XML、CSV等)返回给Curl;
④ Curl取得服务器端传来的数据,进行处理后,以图形、表格或者富文本等形式将结果传送到浏览器。
图1 服务器端联动概念
3.2 服务器端的设定
将开发好的Curl应用程序进行WEB公开时,需要对服务器端进行以下设置。
(1) 许可证密钥(License Key)
许可证密钥是对可以运行Curl应用程序的网站域名进行加密的一个序列文件或二进制文件。即,没有许可证密钥的服务器无法提供Curl服务。Curl提供用于测试的本地(localhost)许可证密钥。从版本3到版本6的本地许可证密钥可从[url]http://www.curlap.com/download/local/[/url] 下载。版本3及版本4的本地许可证密钥可在Surge Lab的的安装目录C:\Program Files\Curl Corporation\Surge\4\etc 或C:\Program Files\Curl Corporation\Surge\5\etc 中找到。这里,C:\Program Files\Curl Corporation\Surge下的4为文本3,5为文本4, 以次类推。每个版本都应有相应版本的许可证密钥文件。其文件名分别是curl-license-3.scurl,curl-license-4.dat, curl-license-5.dat 。版本5和版本6共用curl-license-5.dat文件。实际运用时需要购买正式的许可证密钥。Curl还提供为期两个月的临时许可证密钥以及无偿配置许可证密钥,这两种许可证密钥均要向curl公司提出申请。curl-license-3.scurl等许可证密钥通常放在WEB服务器目录中Curl程序的最高目录下。比如, 使用IIS时,要将其放在c:\Inetpub\wwwroot下面的Curl程序最高等级目录里。许可证密钥放在WEB服务器的根目录也可以。
(2)访问限制
访问限制以文件形式设定。文件名是curl-access.txt。这个文件通常放在WEB服务器的根目录以及需要限制内容的地方。这是为了信息保密而采取的安全措施的一环。如要从没有curl-access.txt许可的服务器执行curl应用程序,则在执行中应用程序会发生SecurityException中断。另外,如果没有设定curl-access.txt,则等于全部不许可。那么,无论从哪个网站执行Curl应用小程序,都会发生同样的SecurityException错误。一般公开的网站需要设定像List 3所示构成的文件。
List 3 curl-access.txt
将开发好的Curl应用程序进行WEB公开时,需要对服务器端进行以下设置。
(1) 许可证密钥(License Key)
许可证密钥是对可以运行Curl应用程序的网站域名进行加密的一个序列文件或二进制文件。即,没有许可证密钥的服务器无法提供Curl服务。Curl提供用于测试的本地(localhost)许可证密钥。从版本3到版本6的本地许可证密钥可从[url]http://www.curlap.com/download/local/[/url] 下载。版本3及版本4的本地许可证密钥可在Surge Lab的的安装目录C:\Program Files\Curl Corporation\Surge\4\etc 或C:\Program Files\Curl Corporation\Surge\5\etc 中找到。这里,C:\Program Files\Curl Corporation\Surge下的4为文本3,5为文本4, 以次类推。每个版本都应有相应版本的许可证密钥文件。其文件名分别是curl-license-3.scurl,curl-license-4.dat, curl-license-5.dat 。版本5和版本6共用curl-license-5.dat文件。实际运用时需要购买正式的许可证密钥。Curl还提供为期两个月的临时许可证密钥以及无偿配置许可证密钥,这两种许可证密钥均要向curl公司提出申请。curl-license-3.scurl等许可证密钥通常放在WEB服务器目录中Curl程序的最高目录下。比如, 使用IIS时,要将其放在c:\Inetpub\wwwroot下面的Curl程序最高等级目录里。许可证密钥放在WEB服务器的根目录也可以。
(2)访问限制
访问限制以文件形式设定。文件名是curl-access.txt。这个文件通常放在WEB服务器的根目录以及需要限制内容的地方。这是为了信息保密而采取的安全措施的一环。如要从没有curl-access.txt许可的服务器执行curl应用程序,则在执行中应用程序会发生SecurityException中断。另外,如果没有设定curl-access.txt,则等于全部不许可。那么,无论从哪个网站执行Curl应用小程序,都会发生同样的SecurityException错误。一般公开的网站需要设定像List 3所示构成的文件。
List 3 curl-access.txt
# curl-access.txt for an Internet Web site
version: 2.0
version: 2.0
allow-all:
(3)MIME类型
需要在WEB服务器添加以下MIME类型:
.curl text/vnd.curl
.scurl text/vnd.curl
.mcurl text/vnd.curl
.dcurl application/vnd.curl.dcurl
.pcurl application/vnd.curl.pcurl
(4)程序包
Cur程序包(启动程序、包等)也需要在服务器端配置。通常最高执行程序的名字是start.curl,构成目录可以是任意的 ,只要能通过浏览器访问即可。
3.3 用XML进行数据通信
设定好服务器后要开始考虑服务的构建。Curl和服务器之间的数据通信形式是没有明确规定的。但常见的应当是CSV或XML。这里介绍被业界视为标准的XML形式。一般来说,XML数据是服务器脚本程序从数据库中抽取数据后加工而成的。Curl应用程序在接收到XML数据后,要使用SAX2简易解析器进行解析,然后通过可视化处理显示到浏览器。服务器端程序由CGI、Servlets和诸如PHP、Perl等各种脚本语言构成,这里以PHP和JSP为例加以说明。
3.3.1 用PHP编写服务器端程序
List 4是用PHP编写的例子query.php。Query.php中将插入List 5所示的xml_maker.php。 Query.php进行从http请求抽取参数,生成SQL请求以及和数据库(ODBC)连接等处理。xml_maker.php则从数据库中抽取检索到的Record,将其加工成List6所示格式的XML数据后返回给客户端 (print文)。
List 4query.php<?php
header( "Cache-Control: no-cache" );
header( "Content-type: text/xml" );
include ("xml_maker.php");
$data_source = "ODBC Data"; //数据库
$region = $HTTP_GET_VARS['para1']; //参数1=region
$year = $HTTP_GET_VARS['para2’]; //参数2=year
//生成SQL文
$sql = "select * from staff where region = '$para1' and year = '$para2'";
$ini_level = error_reporting(0);
//建立连接
if (($connect = odbc_connect ($data_source, "", "")) != 0) {
$len = strlen($sql);
print query_results_xml ($connect, $sql);
odbc_close($connect); //关闭连接
} else {
$err_str = "Could not connect to database: ";
$err_str .= $data_source;
print "<Fault message = '$err_str'/>";
}
error_reporting($ini_level);
?>
List 5 xml_maker.phpfunction escape_xml ($str) {
return htmlspecialchars ($str, ENT_QUOTES);
}
//DB类型转换成Curl类型
$curltypes = array(
'VARCHAR' => 'String',
'DOUBLE' => 'double',
'CURRENCY' => 'double',
'DECIMAL' => 'double',
'INTEGER' => 'int',
'COUNTER' => 'int',
'DATETIME' => 'DateTime',
'BIT' => 'bool',
);
//请求执行后将数据转换成XML返回给客户端。
function query_results_xml ($connect, $sql) {
global $curltypes;
$sql = stripslashes ($sql);
$result = odbc_exec ($connect, $sql);
if ($result == FALSE) {
print "<Fault message = \"$sql\" />";
return;
}
print ("<?xml version=\"1.0\" encoding=\"Shift_JIS\"?>");
$recordset_type = "RecordSet"; //根标签
$record_type = "Record"; //Record标签
print ("<$recordset_type>");
$ncols = (odbc_num_fields ($result));
$fields_type = "Fields"; //Fields标签
$field_type = "Field"; //Field标签
//域信息标签
print ("\n <$fields_type>");
for ( $i = 1; $i <= $ncols; $i++ ){
$key = (odbc_field_name ($result, $i));
$typ = (odbc_field_type ($result, $i));
$curltyp = $curltypes[$typ];
if (strlen ($curltyp) == 0) {
print ("\n <!-- $typ -->");
$curltyp = 'any';
}
print ("\n <$field_type");
print ("\n name = \"$key\"");
print ("\n domain = \"$curltyp\"");
print (" />");
}
print ("\n </$fields_type>");
while (odbc_fetch_row ($result)) {
//Record信息标签
print ("\n <$record_type");
for ( $i = 1; $i <= $ncols; $i++ ){
$key = (odbc_field_name ($result, $i));
$val = (escape_xml (odbc_result ($result, $i)));
print ("\n $key = \"$val\"");
}
print (" />");
}
print ("\n</$recordset_type>");
}
List 6所示的XML格式正好和Curl 6.0的标准类{RecordSet}相对应。Curl应用程序将这些数据转换成{RecordSet}后,再传给{RecordGrid}和{RecordForm}等类,进行富编辑和表现。
List 6 List 5的输出例子(para1=Boston¶2=1962)
<?xml version="1.0" encoding=“Shift_JIS”?>
< RecordSet>
<Fields>
<field name=”name” domain=”String”/>
<field name=”region” domain=”String”/>
<field name=”year” domain=”DateTime”/>
</Fields>
<Record name=”Michael” region=”Boston” year=”1962”/>
<Record name=”Scott” region=”Boston” year=”1962”/>
</RecordSet>
3.3.2 用JSP编写服务器端程序
List 7是使用JSP编写服务器端程序的例子。在这个例子中,数据库是MySQL,数据库名是demo,表是plsum。用List 7的JSP程序输出生成的XML数据如List 8所示。List8的XML和List6的XML相比,List6拥有很多属性,而List8只用了标签。也就是说,XML文本的形式也是没有限制的。系统开发者可根据系统本身的性质对XML形式进行自由设计。
然而, 不管使用PHP还是使用JSP都需要将其引擎和组入WEB服务器中。使用JSP时需要Java SDK和Java Servelet容器(如TOMCAT等)。服务器端的数据可以是任意的数据库或文本文件,但要配有相应的JDBC驱动器。
List 7 用JSP编写的服务器端程序
<%@ page
language="java"
contentType="text/html; charset=Shift_JIS"
import=" java.util.*,java.sql.*, java.lang.*, java.io.*"
%><%
String dep= request.getParameter ("dep"); //参数1
String fis = request.getParameter ("mon"); //参数2
String drv = "com.mysql.jdbc.Driver";// JDBC驱动
String dsn = "jdbc:MySQL://localhost:36.06/demo”+
?user=root&password="; //数据源
String sql = "select * from plsum where yyyymm = '" + fis +
"' and dept = '" + dep+ "' " + "order by unit, mon"; //SQL
try {
Class.forName(drv);
Connection con = DriverManager.getConnection(dsn);
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
int fristRow = rs.getRow();
rs.last();
int lastRow = rs.getRow();
int rows = lastRow - fristRow; //Record数
rs.relative(-rows);
out.println("<?xml version=\"1.0\"
encoding=\"Shift_JIS\"?>"); //XMLヘッダー
out.println("<ResultSet>"); //根标签
out.println("\t<meta>"); // meta标签
out.println("\t\t<sql>" + sql + "</sql>");
out.println("\t\t<rows>" + rows + "</rows>");
out.println("\t</meta>");
int rowNum = 1;
while (rs.next()) { //Record(row)
out.println("\t<row>");
out.println("\t\t<rowid>" + rowNum++ + "</rowid>");
for (int i=1; i<=numberOfColumns; i++) {
String columnName = rsmd.getColumnName (i);
out.println("\t\t<" + columnName + ">" +
rs.getString(i) + "</" + columnName + ">");
}
out.println("\t</row>");
}
out.println("</ResultSet>"); //终止根目录
rs.close();
} catch (Exception e) { //出错处理
out.println ("error");
out.println ("\t<message>" +
"DB access error: " + e.toString() + "</message>");
out.println ("/error");
}
%>
List 8 用List 7输出生成的XML文本
<?xml version="1.0" encoding=“Shift_JIS”?>
< ResultSet >
<meta>
<sql> select * from plsum where … </sql>
<rows>2</rows>
</meta>
<row>
<rowid>1</rowid>
<dept>营业部</dept>
<profit>1200000</profit>
</row>
<row>
<rowid>1</rowid>
<dept>技术部</dept>
<profit>2400000</profit>
</row>
</ResultSet >
3.3.3 Curl对Web服务器的数据请求
在Curl里有和HTML表单(Form)非常相似的类HttpForm。可以用这个类非常容易地设置Http Context, Http Method, 指定调用Http服务的方法(get/post),进行数据验证以及自动发送数据请求。但在大部分情况下,使用HttpFormData这个类,加以手动和HttpRequest组合,可以更灵活地实现数据请求。List 9为一实例。这个实例中定义了2个函数。即,{qx-http-form-data}和{qx-get-http-data}。{qx-http-form-data}可以生成多个key=”val”的{HttpFormData}。通过给{qx-get-http-data} 函数传入URL和{HttpFormData},便可向服务器发送数据请求。 返回的数据被存放在{Array-of StringBuf}中。List 9中的{do}程序块是必须的,向服务器发送数据请求的正是这里。
List 9 Curl向服务器发送数据请求{curl 6.0 applet}
{curl-file-attributes character-encoding=”utf-8”}
{define-proc public {qx-get-http-data
the-url:Url, form-data:HttpFormData}:#{Array-of StringBuf}
let input-stream:#TextInputStream
let lines:#{Array-of StringBuf}
let cnt:#int
{try
let file:HttpFile = {the-url.instantiate-File} asa HttpFile
set input-stream = {file.http-read-open
request-data = form-data,
request-method = HttpRequestMethod.get,
character-encoding= {get-character-encoding-by-name "utf-8"}
}
set (lines, cnt) = {input-stream.read-lines}
catch e:HttpException do
{output {value e}}
catch e:IOException do
{output {value e}}
finally
{if-non-null input-stream then {input-stream.close}}
}
{return lines}
}
{define-proc public {qx-http-form-data ...}:HttpFormData
let form-data:HttpFormData = {HttpFormData
mime-type = HttpFormData.urlencoded-mime-type,
default-character-encoding=
{get-character-encoding-by-name "utf-8"}
}
{for (x, k) in ... do
{if-non-null k then
{form-data.append {new HttpFormStringParam, k, {String x}}}
}
}
{return form-data}
}
||下面是方法
{let form-data:HttpFormData = {qx-http-form-data
dep=”营业部”, mon=”2004/10”
}
{let the-url:Url = {url "http://localhost:8080/query.jsp"}}
{do
let lines:#{Array-of StringBuf}
{try
set lines = {qx-get-http-data the-url, form-data}
{output "Get line master is OK. --> " & lines.size }
catch th:Throwable do
{output "Http access error. Try test data."}
}
}
3.3.4 Curl程序中的XML数据处理
以上说明了如何在服务器站点生成XML数据和如何将数据返回到Curl客户端。此外还讲了如何向服务器端发出数据请求的方法。单是从服务器获取XML数据,那么使用List 9中的{ qx-get-http-data}就可以了。但是,{ qx-get-http-data}获取的仅仅是XML文本。如果不对其进行解析的话,那就不算是富客户端了。解析XML文本可使用Curl内置的SAX2解析器。使用SAX2解析器时,需要明确地导入CURL.XML.SAX.PARSER程序包。
使用SAX2解析XML的步骤如下:
① 先定义好存储XML解析结果的数据区。这里可以使用{RecordSet}、自定义的类或类数组等等;
② 继承{DefaultHandler},定义一个自己的Hander类。这个类必须重载DefaultHandler的5个方法, 即:(1) start-document; (2)start-element; (3)characters; (4)end-element; (5)end-document。 通过这些方法,可以把XML数据解析到相应的数据存储区;
③ 设定{SAXParser}实体的解析用Hander以及错误处理用Hander;
④ 给{SAXParser}实体的parse方法传入XML数据源参数以后,XML的解析过程便开始了。解析过程中,如有发生不符合数据类型结构的数据,那么会自动调用错误处理Hander;
⑤ 解析好的数据可以在浏览器中以树状结构表示出来。
例如,List 10的XML数据结构可以使用List 11中的类和Handler来处理。List 10 XML数据格式
<?xml version=”1.0”?>
<persons>
<person id=”10001”>
<fname>小王</fname>
<lname>小李</lname>
</person>
<person id=”10002”>
<fname>老张</fname>
<lname>老蔡</lname>
</person>
</persons>
List 11 List 10的XML处理程序{curl 6.0 applet}
{import * from CURL.XML.SAX.PARSER} ||显式导入
{define-class public Person ||定义数据解析保存区
field public id:String = ""
field public fname:String = ""
field public lname:String = ""
}
{define-class public MyHandler {inherits DefaultHandler}
field public persons:{Array-of Person}= `Array-of Persons`
field private person:Person= {Person}
field private text:StringBuf={StringBuf} ||test hash
{constructor public {default}
{construct-super}
}
{method public {start-document}:void ||根标签
{self.persons.clear} || 清除
}
{method public {start-element uri:String,
name:String, qname:String, atts:Attributes}:void
{self.text.clear} ||清除文本
{if name == "person" then || person的条件下取id
set self.person = {Person} ||生成新的Person
{for i:int = 0 below {atts.get-length} do
{if {atts.get-qname i} == "id" then
set self.person.id = {{atts.get-value i}.to-String}
}
}
}
}
{method public {characters ch:StringBuf, start:int, ength:int}:void
{self.text.concat{ch.substr start, length}}
} ||链接字符串
{method public {end-element uri:String,
name:String, qname:String}:void
{switch name
case "fname" do ||fname结束
set self.person.fname = {self.text.to-String}
case "lname" do ||lname结束
set self.person.lname = {self.text.to-String}
case "person" do ||person结束
{self.persons.append self.person}
else
}
}
{method public {end-document}:void
} || 终止根标签
}
{let my-parser:SAXParser = {SAXParser}}
{let my-handler:MyHandler = {MyHandler}}
{let my-url:Url} = {url “[url]http://localhost:8080/get-xml.asp[/url]}}
{let my-file:HttpFile = {my-url.instantiate-File} asa HttpFile
{let my-stream:#TextInputStream}
{do || try catch添加异常处理。
set my-stream = {my-file.http-read-open
request-method = HttpRequestMethod.get, character-encoding
={get-character-encoding-by-name "utf-8"}}
{my-parser.set-content-handler my-handler}
{my-parser.set-error-handler my-handler}
{my-parser.parse {InputSource character-stream=my-stream }}
}
{value
|| 追加my-handler.persons的表示code
}
4. 应用程序开发
4.1包
在开发Curl的应用程序时,如果是中小规模的程序,那么仅需建立几个源程序文件,然后将其内插到启动程序start.curl中即可。但是,如要进行大规模开发,则最好使用包。使用包的优点有:
① 程序可以分层同时开发;
② 组件可以共通化;
③ 可以进行压缩;
④ 可以根据需要动态调入(dynamic import);
⑤ 可以不按顺序定义变量和类。
包可以由一个文件构成,也可以由多个文件构成。包的名字可以自由命名,如COM.CURL.XYZ等。包的声明如List 12所示。包文件的扩展名为.scurl。一般来说,包的定义文件名采用load.scurl。当然,根据需要可采用带意义的名字。此外,包还可以单独使用目录。List 12所示的包的名称是COM.QX.SIMPLE-GRID,它包含了3个文件,SimpleDataGrid.scurl、SimpleDataGridPrint.scurl和popup_menus.scurl。和curl内置的标准包一样,也用import来调用。如想在调用包时不指定包的路径,那么需要事先将其定义到manifest文件中。Manifest文件的定义如List13所示,而其调用则如List14所示。通过pcurl化包,可以大幅地压缩源代码。一般来说,可以压缩到1/3。压缩率与源代码的书写风格有关。目前,没有公开的pcurl程序还原方法,所以,在进行pcurl化时需注意保留源代码。用List 15所示的简易程序便可对包pcurl化。Surge Lab(IDE)也有pcurl功能。Pcurl化的包的后缀名是.pcurl。包和应用程序(applet)不同,不会自动导入诸如浏览器接口,图形绘制以及IO等curl内置标准包。所以,开发者需要在包定义文件中,明确地导入相关的标准包和超级标准包。相反,应用程序(applet)则会默认地自动导入许多标准包和超级标准包。List 12 包的定义文件load.scurl{curl 6.0 package}
{package COM.QX.SIMPLE-GRID,
version = "1.0",
{compiler-directives
stringent? = true,
allow-implicit-open? = true,
allow-any-calls? = true,
allow-implicit-any-casts? = true,
allow-slow-spliced-arguments? = true
}
}
{include
"SimpleDataGrid.scurl",
"SimpleDataGridPrint.scurl",
"popup_menus.scurl"
}
{import * from CURL.GUI.STANDARD}
{import * from CURL.GUI.CONTROLS}
{import * from COM.QX.MISC-TOOLS}
List 13 manifest定义文件manifest.mcurl
{curl 6.0 manifest}
{manifest QX_PACKAGE_LOCATIONS,
version = "1.0"
}
{component package COM.QX.CHART,
location = "../chart/load.scurl"
}
{component package COM.QX.TREE,
location = "../utility/tree/load.scurl"
}
{component package COM.QX.SIMPLE-GRID,
location = "../sdg/load.scurl"
}
List 14 在start.curl中指定manifest
{curl 6.0 applet}
{curl-file-attributes character-encoding = "utf-8"}
{applet manifest = "./manifest/manifest.mcurl"}
{import * from COM.QX.COMMONS}
|| 以下为主要源程序。
List 15 将包pcurl化的程序
{curl 6.0 applet}
Start...
{let applet:Applet = {get-the-applet}}
{do
{pcurl-file {url "xml/load.scurl"}}
{applet.set-status "1/3"}
{applet.flush}
{pcurl-file {url "sdg/load.scurl"}}
{applet.set-status "2/3"}
{applet.flush}
{pcurl-file {url "util/load.scurl"}}
{applet.set-status "3/3"}
{applet.flush}
}
End
4.2 程序的构建
图2 程序的分层
如图2所示,Curl程序的开发大体可以分为四层,即①数据层、②模型层、③表现(显示)层、④布局层。各层都有数据保持和表现的静态结构以及从数据到数据和从数据到表现的动态转换结构。各层是纵向连接处理,主要组件有回调和程序间的通信处理的。一般来说,各组件根据层和功能分成包进行开发。包的路径(location)一般是由manifest管理的。如果能完善地设计各组件之间的接口,那么就可以实现平行开发;如果能完善地设计并构建各组件,那么维护将变得更加简单,并且可以进行再利用。多数情况下,应用程序是由这些组件组成的,因此,图2中的组件被称为应用程序的基础组件。 从版本2起,Curl公司提供了供参考的CSK(Curl Starter Kit)来进行基础组件的开发。CSK拥有如图2所示的所有组件。CSK有代码、文档和例子,不仅可以参考,还能进行改造和扩展,可以变成很有用的组件。图3和图4是用扩展的chart包COM.QX.CHART作成的重叠图形。Curl的版本4提供了基于Shape类的内置作图包CURL.GUI.CHARTS。
如果没有扩充源代码的必要,那么,采用CURL.GUI.CHARTS比较轻便。
如果没有扩充源代码的必要,那么,采用CURL.GUI.CHARTS比较轻便。
图3 柱状图和折线图叠加
图4堆积棒形图和水平线图
图5用CURL.GUI.CHARTS绘制的图例
图5用CURL.GUI.CHARTS绘制的图例
Table(表)组件有标准的{Table}和{RecordGrid}。图6是{RecordGrid}的一个例子。使用{RecordGrid}可以通过{BasicConnection}和{RecordSet}以及其下位类的联动,经由服务器直接从数据库取得Record数据,并将其表示出来。
图6RecordSet}展开成{RecordGrid}的例子
不过,在构建GUI的时候,我们也可以自己定义特殊的表格。图7就是自己制作的多滚动条表格组件{SimpleDataGrid}。
图7{ScrollBox}{Vbox}{Hbox}{Frame}构成的表格
布局指的是由Chart或者Table组成的,在浏览器里显示的画面。标准布局组件有{TabConTainer}、{PanedWindow},这些组件可以互相嵌套使用。图8是由CSK的{PFStaticLayout}扩展成的2x2画面。应用程序的最前端就是布局画面,最终用户看见的就是布局画面。图9所示的是一典型的四分割多窗口布局。每个窗口都是同样的应用程序,然而,通过选择每个窗口左侧的蠕动菜单,可以显示不同的表格和图形。
图8页面(可以拖拽和拉伸)
图9 多窗口布局
5.总结
以上介绍了Curl的特征、语法基础、富客户端系统的服务器连接和应用程序开发。尽管Curl的魅力远不止这些,但是利用这些知识应该能够构建出很不错的应用程序了。如果能利用Curl的3D图形功能、音频功能、ActiveX功能以及网络服务(Web Service)的话,一定可以创造出难以想象的优秀的WEB应用程序。
Curl语言接受了十几年的风吹雨打,在与时俱进地走向 成熟。由最初的版本1.x.x起,现已升级到版本7.0B。
版本3主要加强了RecordGrid等类; 版本4主要加强了绘图功能等;版本5进一步增强了RecordGrid功能以及增加了数据加密技术; 版本6主要增强了与JavaScript联运功能;版本7主要增强的功能有Eclipse统合开发环境,绘图功能和安全功能等。
参考资料:
[1] Jetzt lerne ich Curl 2.0. Der einfache Einstieg in eine neue Websprache, Arens, Manfred, Perfect (2002/11) Markt + Technik, Mchn
[2] Surge Lab Documentation (6.0), Curl Corporation (2004)
以上介绍了Curl的特征、语法基础、富客户端系统的服务器连接和应用程序开发。尽管Curl的魅力远不止这些,但是利用这些知识应该能够构建出很不错的应用程序了。如果能利用Curl的3D图形功能、音频功能、ActiveX功能以及网络服务(Web Service)的话,一定可以创造出难以想象的优秀的WEB应用程序。
Curl语言接受了十几年的风吹雨打,在与时俱进地走向 成熟。由最初的版本1.x.x起,现已升级到版本7.0B。
版本3主要加强了RecordGrid等类; 版本4主要加强了绘图功能等;版本5进一步增强了RecordGrid功能以及增加了数据加密技术; 版本6主要增强了与JavaScript联运功能;版本7主要增强的功能有Eclipse统合开发环境,绘图功能和安全功能等。
参考资料:
[1] Jetzt lerne ich Curl 2.0. Der einfache Einstieg in eine neue Websprache, Arens, Manfred, Perfect (2002/11) Markt + Technik, Mchn
[2] Surge Lab Documentation (6.0), Curl Corporation (2004)
转载于:https://blog.51cto.com/qualitech/130218