热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

详解XML与现代CGI应用程序的示例代码

Perl的普及与互联网的蓬勃发展有直接的关系。Perl强大的功能和容易扩充的特性使得它成为开发CGI应用最自然的选择,并由此迅速地成为CGI脚本的首选语言。CGI本身并非十全十美。但由于得到了众多开发商的青睐,CGI的应用至今仍然十分广泛,而且没有迹象表明在近期会“退休”。
简介

Perl的普及与互联网的蓬勃发展有直接的关系。Perl强大的功能 和容易扩充的特性使得它成为开发CGI应用最自然的选择,并由此迅速地成为CGI 脚本的首选语言。CGI本身并非十全十美。但由于得到了众多开发商的青睐,CGI 的应用至今仍然十分广泛,而且没有迹象表明在近期会“退休”。

典型的CGI::XMLApplication脚本包括三部分:一个很小的提供对该应用 程序访问支持的可执行脚本、实现各种管理者方法的逻辑模块、根据应用状态可 能有一个或多个XSLT样式表,XSLT样式表能够将模块返回的结果转化成浏览器可 以向用户显示的格式。

下面我们通过例子来简要地介绍 CGI::XMLApplication的应用。

例1:CGI XSLT网关

CGI::XMLApplication假定,参与一个项目的设计和开发人员使用XSLT样 式表分离应用的逻辑和表示,这样可以使这种分离显得非常直接,也不会对项目 带来影响。开发人员只要能够使setStylesheet返回符合当前应用状态的XSLT样式 表的位置即可。应用建立的DOM树的转换、XSLT参数向转换引擎的传递、转换后内 容向浏览器的传输对用户而言都是透明的。

为了重点说明这种分离,我们 的第一个例子不是传统意义上的Web应用,而是一个通用的XSLT网关,它可以添加 到服务器的cgi-bin中,将整个XML内容的目录树转化为符合请求的浏览器的格式 ,而这一切对于用户、样式表和文档的作者而言也都是透明的。

第一步是 建立连接客户端的请求和应用的CGI脚本。我们希望XML文档能够方便地通过URL浏 览,并使创建这些文档间的超链接非常直观。因此,我们将创建一个没有扩展名 的CGI脚本,以便将它作为URL路径中的一个节点,节点右边的所有内容将在包含 XML内容的虚拟文档环境中进行解释。在这种情况下,我们将CGI称作是样式表选 择者。

use strict;
use lib '/path/to/secure/webapp/libs';
use XSLGateway;
use CGI qw(:standard);my $q = CGI->new();
my %cOntext= ();
my $gateway_name = 'stylechooser';

在加载合适的模块和设置 一些在整个脚本范围内有效的变量后,我们开始向被传递给处理该应用逻辑的类 的%context中添加一些域。在这个应用软件中,我们只传输要求的指向脚本文件 路径右边的URL(REQUEST条目)和包含有存储在查询参数style中的数据的STYLE 关健字。

$context{REQUEST} = $q->url(-path => 1);
$context{REQUEST} =~ s/^$gateway_name/?//;
$context{REQUEST} ||= 'index.xml';
$context{STYLE} = $q->param ('style') if $q->param('style');

最后,我们 创建了XSLGateway逻辑类的一个实例,并通过调用其run方法处理请求,将% context作为唯一的参数。

my $app = XSLGateway->new();
$app->run(%context);

CGI脚本就完成了。下面我们创建完成大 部分工作的XSLGateway模块:

package XSLGateway;
use strict;
use vars qw(@ISA);
use CGI::XMLApplication;
use XML::LibXML;
@ISA = qw(CGI::XMLApplication);

象我在简介中 提到的那样,CGI::XMLApplication通过事件调用起作用:应用程序类中一个给定 的方法的执行依赖于一个指定域的输入(一般情况下是用来提交表格的按钮的名 字。),必须执行二种调用方法:selectStylesheet和requestDOM方法。

selectStylesheet返回有关的XSLT样式表的全文件系统路径。为了简单起 见,我们假定样式表将保存在一个单一的目录中。我们可以通过$context-> {STYLE}域提供其他的样式表,从而增加系统的灵活性。

sub selectStylesheet {
my $self = shift;
my $cOntext= shift;
my $style = $context->{STYLE} || 'default';
my $style_path = '/opt/www/htdocs/stylesheets/';
return $style_path . $style . '.xsl';
}

下一步,我们需要 创建requestDOM方法,该方法将返回被传输的XML文档的XML::LibXML DOM表达式 。由于我们的网关只适用于静态文件,我们需要使用XML::LibXML对文档进行解析 ,并返回结果树。

sub requestDOM {
my $self = shift;
my $cOntext= shift;
my $xml_file = $context->{REQUEST} || 'index.xml';
my $doc_path = '/opt/www/htdocs/xmldocs/';
my $requested_doc = $doc_path . $xml_file;
my $parser = XML::LibXML->new;
my $doc = $parser->parse_file($requested_doc);
return $doc;
}

至此,我们的CGI脚本已经可以安全地在服务器的cgi-bin目录中安全 地运行了,并在一些适当的目录中上载一些XML文档和一个或二个XSLT样式表。下 面我们就可以开始检验我们的工作成果了。对localhost/cgi- bin/stylechooser/mydocs/somefile.xml的请求将会使互联网服务器 从/opt/www/htdocs/xmldocs/目录中选取mydocs/somefile.xml文件,使 用/opt/www/htdocs/stylesheets/中的样式表default.xsl对该文件进行转换,并 将它传输给客户。

如果需要,我们可以扩充这一基本的框架,例如,可以 在样式表选择CGI脚本程序添加一些查找组件,选择合适的样式表,可以设置或读 取HTTP COOKIEs,对网站进行修饰。

例2:一个简单的购物系统

在 该例子中,我们将使用CGI::XMLApplication创建一个简化的Web应用程序,购物 系统。

与上个例子相同,这个应用程序中与CGI-BIN有关的部分仍然非常 地少。我们所需要作的只不过是初始化CustomerOrder应用类并调用它的run()方 法。这次,我们将CGI.pm中Vars作为%context的PARAMS域:

use strict;
use CGI qw(:standard);
use lib '/path/to/secure/webapp/libs';
use CustomerOrder;
my $q = CGI->new();
my %cOntext= ();
$context{PARAMS} = $q- >Vars;
my $app = CustomerOrder->new();
$app->run(% context);

在这个例子中,我们假定该应用中的产品信息存储在关 系数据库中,产品清单不是太长,使我们在应用中不会出现多屏才能显示相关信 息的麻烦:用户输入订购的产品数量的主要数据输入屏,显示订购单内容和所选 物品总价格的确认屏,显示订单已经处理的提示。为了简单起见,我们在这里没 有涉及送货和财务数据的输入等问题。

package CustomerOrder;
use strict;
use vars qw(@ISA);
use CGI::XMLApplication;
use XML::LibXML::SAX::Builder;
use XML::Generator::DBI;
use DBI;
@ISA = qw (CGI::XMLApplication);

在加载必要的模块和定义从 CGI::XMLAplication中继承的类后,我们开始创建应用中与各种状态有关的事件 调用。首先,我们必须通过创建registerEvents()方法注册这些事件。在本例中 ,我们将注册order_confirm 和order_send方法,这二个方法设置%context中的 SCREENSTYLE域。稍后,我们将利用该属性定义在显示客户端的数据时应该使用三 个XSLT样式表中的哪一个。

需要注意的是,这些事件将被映射到实现它们 的实际的子程序中,子程序的命名规则是event_<事件名>,例如, order_confim事件是由event_order_confim执行的。另外,还需要注意的是,各 种事件的选择是由CGI::XMLApplication根据其查找一个与注册事件同名的表格参 数的能力进行的。例如,要执行order_confirm事件,表格组件中必须包含一个提 交非空值的名字为order_confirm的表格域。

# 事件的注册和事件调用

sub registerEvents {
return qw( order_confirm order_send );
}
sub event_order_confirm {
my ($self, $context) = @_;
$context->{SCREENSTYLE} = &#39;order_confirm.xsl&#39;;
}
sub event_order_send {
my ($self, $context) = @_;
$context->{SCREENSTYLE} = &#39;order_send.xsl&#39;;
}

如果没有请求执行其他的事 件,则缺省地执行event_default。在本例中,我们只使用它将SCREENSTYLE域设 定为一个合适的值。

sub event_default {
my ($self, $context) = @_;
$context->{SCREENSTYLE} = &#39;order_default.xsl&#39;;
}

每次请求都会执行 event_init方法,而且总是在其他方法之前执行它,这使得它非常适合对应用中 被其他事件使用的部分进行初始化。在本例中,我们使用它返回利用 fetch_recordset()方法从数据库中获取的产品信息的、最初的DOM树。

sub event_init {
my ($self, $context) = @_;
$context->{DOMTREE} = $self->fetch_recordset();
}

state-handler方法完成后,我们需要执行必需的 selectStylesheet和requestDOM方法。

与在第一个例子中一样,我们假设 所有的应用的样式表都存储在服务器上相同的目录中。我们所需要作的是返回 $context->{SCREENSTYLE}的值所指定的路线,并添加到末尾。

# app config and helpers
sub selectStylesheet {
my ($self, $context) = @_;
my $style = $context-> {SCREENSTYLE};
my $style_path = &#39;/opt/www/htdocs/stylesheets/cart/&#39;;
return $style_path . $style;
}

在研究requestDOM处理程序之前,我们先来详细 地研究fetch_recordset helper方法。

需要记住的是,我们要做的工作是 从一个关系数据库中选择所订购产品的有关信息,但传递给XSLT处理器的数据必 须是DOM树。在本例中,我们不通过编程的方法,而是利用XML::Generator::DBI ,它能够从执行SQL SELECT语句得到的数据中生成SAX数据。创建要求的DOM树就 是建立XML::LibXML::SAX::Builder(它从SAX事件中创建XML::LibXML DOM树)的 实例。

sub fetch_recordset {
my $self = shift;
my $sql = &#39;select id, name, price from products&#39;;
my $dbh = DBI->connect(&#39;dbi:Oracle:webclients&#39;,
&#39;chico&#39;,
&#39;swordfish&#39;)
|| die "database connection couldn&#39;t
be initialized: $DBI::errstr n";
my $builder = XML::LibXML::SAX::Builder->new();
my $gen = XML::Generator::DBI->new(Handler => $builder,
dbh => $dbh,
RootElement => &#39;document&#39;,
QueryElement => &#39;productlist&#39;,
RowElement => &#39;product&#39;);
my $dom = $gen->execute($sql) || die "Error Building DOM Treen";
return $dom;}

fetch_recordset方法完成了另一项很重要的任务,但它返回的 DOM树只包含我们想向客户发送信息的一部分,我们还必须获取用户输入的产品数 量,另外,还需要提供一个订购产品的总计。

sub requestDOM {
my ($self, $context) = @_;
my $root = $context-> {DOMTREE}->getDocumentElement();
my $grand_total = &#39;0&#39;;

为了将当前的订货数量作为更大的文档的一部分, 我们将遍历所有的产品元素,并在每行中添加和子元素。的值可以从$context- >{PARAMS}域获得。

foreach my $row ($root->findnodes (&#39;/document/productlist/product&#39;)) {
my $id = $row- >findvalue(&#39;id&#39;);
my $cost = $row->findvalue (&#39;price&#39;);
my $quantity = $context->{PARAMS}->{$id} || &#39;0&#39;;
my $item_total = $quantity * $cost;
$grand_total += $item_total;
# add the order quantity and item totals to the tree.
$row->appendTextChild(&#39;quantity&#39;, $quantity);
$row->appendTextChild(&#39;item-total&#39;, $item_total);
}

最后,我们将增加一些有关订单的元信息 ,方法是在具有元素的根元素中添加一个元素,该元素中包含有当前所选货物的 总价值。

$grand_total ||= &#39;0.00&#39;;
my $info = XML::LibXML::Element->new(&#39;instance-info&#39;);
$info- >appendTextChild(&#39;order-total&#39;, $grand_total);
$root- >appendChild($info);
return $context->{DOMTREE};
}

细心的读者可能已经注意到,我们这个非常简单的应用程序在 order_send方法中没有作任何实际的事。决定如何处理这些数据是产品订购应用 程序中与具体的购物网站最有关的部分。

结束语

CGI::XMLApplication在CGI脚本程序的编程中提供了一种清晰的、模块化 的隔离系统的内容和表示的方法,单就这一点,就值得我们对它进行一番研究。 此外,它还可以使我们避免纠缠于一些细节问题,而集中精力解决主要的问题。

以上就是详解XML与现代CGI应用程序的示例代码的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 腾讯安全平台部招聘安全工程师和数据分析工程师
    腾讯安全平台部正在招聘安全工程师和数据分析工程师。安全工程师负责安全问题和安全事件的跟踪和分析,提供安全测试技术支持;数据分析工程师负责安全产品相关系统数据统计和分析挖掘,通过用户行为数据建模为业务决策提供参考。招聘要求包括熟悉渗透测试和常见安全工具原理,精通Web漏洞,熟练使用多门编程语言等。有相关工作经验和在安全站点发表作品的候选人优先考虑。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
author-avatar
书友76075933
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有