當(dāng)前位置:工程項(xiàng)目OA系統(tǒng) > 泛普各地 > 上海OA系統(tǒng) > 上海OA快博
用Perl和XML輕松開(kāi)發(fā)多種界面的Web服務(wù)
申請(qǐng)免費(fèi)試用、咨詢電話:400-8352-114
AMTeam.org用Perl和XML輕松開(kāi)發(fā)多種界面的Web服務(wù)
簡(jiǎn)介
與Web服務(wù)有關(guān)的的一個(gè)基本問(wèn)題是如何創(chuàng)建一個(gè)既能夠通過(guò)基于瀏覽器的客戶端又能夠通過(guò)編程方式讓客戶端自動(dòng)訪問(wèn)應(yīng)用程序。在本文中,我們將討論如何利用Perl和XML簡(jiǎn)單地創(chuàng)建多界面的Web服務(wù)。
我們之所以選擇Perl和XML,與SOAP、XML-RPC和REST的優(yōu)缺點(diǎn)無(wú)關(guān),也不是為了試圖解決哪種工具更適合用來(lái)開(kāi)發(fā)Web服務(wù)的問(wèn)題。我們?cè)谶@里想要說(shuō)明的是,只要?jiǎng)狱c(diǎn)腦筋并使用一些Perl模塊,就可以創(chuàng)建出實(shí)用的而且能夠通過(guò)多種客戶端進(jìn)行訪問(wèn)的Web服務(wù)。
例子━━WebSemDiff:多界面的XML Semantic Diff Web服務(wù)
在本篇文章中,我們將建立XML::SemanticDiff模塊的一個(gè)Web界面。XML::SemanticDiff能夠在忽略細(xì)節(jié)的情況下比較二個(gè)XML文檔的內(nèi)容。
閱讀本文之前,我建議讀者應(yīng)當(dāng)對(duì)CGI::XMLApplication有個(gè)基本的了解。對(duì)它有一定的了解會(huì)對(duì)理解我們本篇文章的內(nèi)容有所幫助。事實(shí)上只要了解一個(gè)典型的包括三個(gè)部分的CGI::XMLApplication應(yīng)用程序就夠了:連接客戶端和應(yīng)用程序的CGI腳本、處理任務(wù)的Perl模塊以及將Perl模塊中返回的DOM樹(shù)轉(zhuǎn)換為客戶端應(yīng)用程序能夠接受的XSLT樣式表。
理解CGI::XMLApplication的基本架構(gòu)是十分重要的,因?yàn)镾OAP::Lite模塊也使用了相同的架構(gòu),開(kāi)發(fā)多客戶端訪問(wèn)應(yīng)用的根本目的在于對(duì)這二個(gè)模塊整合的理解。
首先,我們來(lái)看看CGI::XMLApplication和SOAP::Lite用來(lái)比較上傳到服務(wù)器的文件所使用的基本模塊:
package WebSemDiff;
use strict;
use
CGI::XMLApplication;
use XML::SemanticDiff;
use
XML::LibXML::SAX::Builder;
use XML::Generator::PerlData;
use vars qw( @ISA );
@ISA = qw( CGI::XMLApplication
);
在導(dǎo)入必要的模塊以及聲明軟件包與CGI::XMLApplication的繼承關(guān)系后,我們需要實(shí)現(xiàn)使瀏覽器界面工作的方法。
瀏覽器界面有二種狀態(tài):缺省狀態(tài)是提醒用戶上傳二個(gè)XML文檔進(jìn)行比較,顯示比較結(jié)果的結(jié)果狀態(tài)(或在比較時(shí)出現(xiàn)的錯(cuò)誤)。selectStylesheet()方法返回由應(yīng)用程序生成的DOM樹(shù)轉(zhuǎn)換成的樣式表的路徑。在這里我們不對(duì)semdiff_default.xsl和semdiff_result.xsl這二個(gè)樣式表進(jìn)行詳細(xì)的討論。
sub selectStylesheet {
my ( $self, $context ) = @_;
my
$style = $context->{style} || 'default';
my $style_path =
'/www/site/stylesheets/';
return $style_path . 'semdiff_' . $style .
'.xsl';
}
缺省情況下,必需的getDOM()方法將返回一個(gè)XML::LibXML::Document對(duì)象。在向?yàn)g覽器返回結(jié)果前,由selectStylesheet()方法設(shè)定的XSLT樣式表將對(duì)該文檔對(duì)象進(jìn)行轉(zhuǎn)換。
sub getDOM {
my ( $self, $context ) = @_;
return
$context->{domtree};
}
getXSLParameter()方法提供了從類向樣式表傳送值的一種方式(可以通過(guò)<xsl:param>元素獲得該值)。在這里,我們只增加所有的請(qǐng)求參數(shù),讓樣式表來(lái)選擇相關(guān)的域。
sub getXSLParameter {
my $self = shift;
return
$self->Vars;
}
由于缺省狀態(tài)只是一個(gè)不要求應(yīng)用程序邏輯或特別處理的簡(jiǎn)單提示,因此我們只需實(shí)現(xiàn)對(duì)結(jié)果狀態(tài)的訪問(wèn)即可:
# 登錄事件和回調(diào)事件
sub registerEvents {
return qw( semdiff_result
);
}
sub event_semdiff_result {
my ( $self, $context ) = @_;
my
( $file1, $file2, $error );
my $fh1 = $self->upload('file1');
my $fh3 =
$self->upload('file2');
$context->{style} = 'result';
在為應(yīng)用程序的狀態(tài)設(shè)置合適的樣式后,我們就能夠獲得包含有上傳的XML文檔的文件句柄。我們首先檢查二個(gè)句柄是否存在,如果存在,則轉(zhuǎn)換為二個(gè)簡(jiǎn)單的標(biāo)量:
if ( defined( $fh1 ) and defined( $fh3 ) ) {
local $/ =
undef;
$file1 = <$fh1>
$file2 = <$fh3>;
其次,我們創(chuàng)建包含由通過(guò)調(diào)用compare_as_dom()方法生成的比較結(jié)果的DOM樹(shù)。將這次調(diào)用封裝在一個(gè)eval塊中,以確保我們能夠獲得在處理上傳的文檔時(shí)發(fā)生的解析錯(cuò)誤。在稍后,我們將仔細(xì)地研究 compare_as_dom()和dom_from_data()方法。
eval {
$context->{domtree} = $self->compare_as_dom( $file1,
$file2 );
};
if ( $@ ) {
$error = $@;
}
}
else {
$error = 'You
must select two XML files to compare
and wait for them to finish
uploading';
}
if ( $error ) {
$context->{domtree} = $self->dom_from_data( {
error => $error } );
}
如果二個(gè)文檔完全相同,compare_as_dom()返回一個(gè)示定義的字符。如果沒(méi)有返回DOM對(duì)象,也沒(méi)有錯(cuò)誤產(chǎn)生,我們創(chuàng)建一個(gè)只包含告訴用戶二個(gè)文檔相同的一個(gè)<message>元素的文檔。
unless ( defined( $context->{domtree} )) {
my $msg = "Files
are semantically identical.";
$context->{domtree} = $self->dom_from_data( {
message => $msg } );
}
}
在完成信號(hào)收集事件后,我們就可以繼續(xù)編寫信號(hào)收集事件和SOAP調(diào)度程序共享的核心方法了。
首先,我們需要來(lái)創(chuàng)建compare()方法。它不僅僅是同名的XML::SemanticDiff的方法的容器,它還接受二個(gè)包含被比較的XML文檔的句柄并返回結(jié)果。
sub compare {
my $self = shift;
my ( $xmlstring1,
$xmlstring2 ) = @_;
my $diff = XML::SemanticDiff->new( keeplinenums => 1
);
my @results = $diff->compare( $xmlstring1, $xmlstring2 );
return
@results;
}
dom_from_data()方法通過(guò)XML::Generator::PerlData對(duì)任何公用Perl數(shù)據(jù)結(jié)構(gòu)的引用進(jìn)行處理創(chuàng)建一個(gè)XML::LibXML::Document對(duì)象(DOM樹(shù)形式的XML文檔),并將生成器與XML::LibXML::SAX::Builder連接生成DOM樹(shù)。還記得嗎,我們?cè)诮Y(jié)果事件回調(diào)中調(diào)用了該方法來(lái)創(chuàng)建包含有適當(dāng)信息的DOM樹(shù)。
sub dom_from_data {
my ( $self, $ref ) = @_;
my $builder =
XML::LibXML::SAX::Builder->new();
my $generator =
XML::Generator::PerlData->new( Handler => $builder );
my $dom =
$generator->parse( $ref );
return $dom;
}
最后,我們將創(chuàng)建compare_as_dom()方法。它也是最后的二個(gè)方法的容器,它以DOM樹(shù)的形式返回二個(gè)文檔的比較。
sub compare_as_dom {
my $self = shift;
my $diff_messages =
$self->compare( @_ );
return undef unless scalar( @{$diff_messages} ) >
0;
return $self->dom_from_data( { difference => $diff_messages }
);
}
1;
在創(chuàng)建了上面的方法后,我們就僅需要?jiǎng)?chuàng)建提供能夠供各種客戶端應(yīng)用程序訪問(wèn)的CGI腳本了,這也是需要綜合利用CGI::XMLApplication和SOAP::Lite 的地方。
#!/usr/bin/perl -w
use strict;
use
SOAP::Transport::HTTP;
use WebSemDiff;
if ( defined( $ENV{'HTTP_SOAPACTION'} ))
{
SOAP::Transport::HTTP::CGI
-> dispatch_to('WebSemDiff')
->
handle;
}
else {
my $app = WebSemDiff->new();
$app->run();
}
SOAP::Lite的dispatch_to()方法連接SOAP與一特定的模塊(或模塊的目錄)。在本例中,它使我們能夠重用實(shí)現(xiàn)瀏覽器界面的WebSemDiff類,模塊的共享意味著CGI只不過(guò)是一個(gè)請(qǐng)求代理,它提供了對(duì)基于連接客戶端應(yīng)用應(yīng)用程序類的方法的訪問(wèn)。通過(guò)互聯(lián)網(wǎng)瀏覽器訪問(wèn)應(yīng)用程序的用戶被提示上傳二個(gè)XML文檔,并通過(guò)compare_as_dom()方法獲取結(jié)果,SOAP客戶端只可以直接訪問(wèn)compare_as_dom、更低級(jí)的compare()等方法。
至此,我們已經(jīng)開(kāi)發(fā)了一個(gè)能夠運(yùn)行的應(yīng)用程序。下面我們就來(lái)用一些客戶端與它進(jìn)行連接,比較二個(gè)文檔,并返回相應(yīng)的結(jié)果。
為了簡(jiǎn)明起見(jiàn),我們將使被比較文檔盡量簡(jiǎn)單。第一個(gè)文檔的名字為doc1.xml:
<?xml version="1.0"?>
<root>
<el1 el1attr="good"/>
<el2
el2attr="good">Some Text</el2>
<el3/>
</root>
第二個(gè)XML文檔的名字為:doc2.xml :
<?xml version="1.0"?>
<root>
<el1 el1attr="bad"/>
<el2
bogus="true"/>
<el4>Rogue</el4>
</root>
從瀏覽器進(jìn)行訪問(wèn)
對(duì)/cgi-bin/semdiff.cgi的請(qǐng)求將提示用戶上傳二個(gè)文檔:
圖1
在對(duì)文件進(jìn)行比較后,結(jié)果如下:
圖2
從SOAP客戶端訪問(wèn)
SOAP::Lite既有服務(wù)器也有客戶端實(shí)現(xiàn)。在這里我們將使用它創(chuàng)建一個(gè)連接我們的應(yīng)用程序的SOAP界面的客戶端應(yīng)用程序。為了節(jié)約篇幅,我們將跳過(guò)與變量處理、打開(kāi)和讀取要比較的XML文檔相關(guān)的客戶端腳本,而重點(diǎn)討論與SOAP相關(guān)的部分:
#!/usr/bin/perl -w
use strict;
use
SOAP::Lite;
...
my $soap = SOAP::Lite
->
uri('http://my.host.tld/WebSemDiff')
->
proxy('http://my.host.tld/cgi-bin/semdiff.cgi')
-> on_fault(
&fatal_error );
my $result = $soap->compare( $file1, $file2 )->result;
print "Comparing $f1 and $f2...n";
if ( defined $result and scalar( @{$result} ) == 0 ) {
print
"Files are semantically identicaln";
exit;
}
foreach my $diff ( @{$result} ) {
print $diff->{context} . '
' .
$diff->{startline} . ' - ' .
$diff->{endline} . ' '
.
$diff->{message} .
"n";
}
將我們的二個(gè)XML文檔的路徑傳遞給該腳本代碼會(huì)產(chǎn)生下面的結(jié)果:
Comparing docs/doc1.xml and docs/doc2.xml...
/root[1]/el1[1]
3 - 3 Attribute 'el1attr' has different value in element
'el1'.
/root[1]/el2[1] 4 - 4 Character differences in element
'el2'.
/root[1]/el2[1] 4 - 4 Attribute 'el2attr' missing from element
'el2'.
/root[1]/el2[1] 4 - 4 Rogue attribute 'bogus' in element
'el2'.
/root[1] 5 - 5 Child element 'el3' missing from element
'/root[1]'.
/root[1] 5 - 5 Rogue element 'el4' in element '/root[1]'.
另外,我們可以使用SOAP::Lite的自動(dòng)調(diào)度機(jī)制來(lái)提高代碼的可讀性:
use SOAP::Lite +autodispatch =>
uri =>
'http://my.host.tld/WebSemDiff',
proxy
=>'http://my.host.tld/cgi-bin/semdiff.cgi',
on_fault => &fatal_error
;
my $result = SOAP->compare( $file1, $file2 );
print "Comparing $f1 and $f2...n";
# etc ..
從RESTful客戶端進(jìn)行訪問(wèn)
REST架構(gòu)的愛(ài)好者會(huì)非常喜歡我們的應(yīng)用程序能夠提供訪問(wèn)未經(jīng)轉(zhuǎn)換的XML文檔。
#!/usr/bin/perl -w
use strict;
use
HTTP::Request::Common;
use LWP::UserAgent;
my ( $f1, $f2 ) = @ARGV;
usage() unless defined $f1 and -f $f1
and defined $f2 and -f
$f2;
my $ua = LWP::UserAgent->new;
my $uri = "http://my.host.tld/cgi-bin/semdiff.cgi";
my $req = HTTP::Request::Common::POST( $uri,
Content_Type
=> 'form-data',
Content => [
file1 => [ $f1 ],
file2 => [ $f2
],
passthru => 1,
semdiff_result => 1,
]
);
my $result =
$ua->request( $req );
if ( $result->is_success ) {
print
$result->content;
}
else {
warn "Request Failure: " . $result->message
. "n";
}
sub usage {
die "Usage:nperl $0 file1.xml file2.xml
n";
}
該腳本(restful_semdiff.pl)能夠?qū)⑾旅娴腦ML文檔輸出到STDOUT:
<?xml version="1.0"
encoding="UTF-8"?>
<document>
<difference>
<context>/root[1]/el1[1]</context>
<message>
Attribute
'el1attr' has different
value in element
'el1'.
</message>
<startline>3</startline>
<endline>3</endline>
</difference>
<difference>
<context>/root[1]/el2[1]</context>
<message>
Character
differences in element
'el2'.
</message>
<startline>4</startline>
<endline>4</endline>
</difference>
...
</document>
結(jié)論
在本文中我們完全沒(méi)有提到XML-RPC,原因有二個(gè):
第一,SOAP::Lite提供的XML-RPC客戶端和服務(wù)器端界面與SOAP使用的非常相似,因此使用它意義不大。
第二,與SOAP客戶端不同的是,XML-RPC客戶端沒(méi)有與它們的請(qǐng)求相關(guān)聯(lián)的標(biāo)準(zhǔn)和明確的HTTP頭部,這意味著我們的CGI請(qǐng)求代理必須采取一定的措施來(lái)區(qū)分XML-RPC客戶端和正常的互聯(lián)網(wǎng)瀏覽器。通過(guò)對(duì)POST請(qǐng)求和“text/xml”的內(nèi)容類型進(jìn)行檢查,探測(cè)XML-RPC請(qǐng)求是可能的,但這種方案是“不健壯的”。
通過(guò)本篇文章的介紹,我衷心地希望讀者能夠掌握結(jié)合利用SOAP::Lite和CGI::XMLApplication創(chuàng)建簡(jiǎn)潔、模塊化的支持通過(guò)SOAP、REST和HTML瀏覽器進(jìn)行訪問(wèn)的應(yīng)用程序的方法。
- 1為你的網(wǎng)絡(luò)服務(wù)制作文檔
- 2Amazon和Google開(kāi)辟Web service新紀(jì)元
- 3用戶認(rèn)證和數(shù)字證書為Web服務(wù)保安全
- 4知識(shí)型企業(yè)的上海OA策略(By AMT 宋亮)
- 5Web Services和J2EE:集成中的伙伴
- 6Web技術(shù)、上海OA與高等教育(by AMT 劉宇 編譯)
- 7OA辦公軟件系統(tǒng)中任務(wù)管理是企業(yè)老板最關(guān)心的功能
- 8上海OA戰(zhàn)略
- 9數(shù)字資產(chǎn)管理:捕獲競(jìng)爭(zhēng)優(yōu)勢(shì)的新方式(by AMT 劉宇 編譯)
- 10經(jīng)驗(yàn)知識(shí)的獲取和作用
- 11上海OA--衰退期成長(zhǎng)的動(dòng)力
- 12WEB服務(wù)“不是”什么
- 13Web服務(wù)與二進(jìn)制傳輸
- 14將經(jīng)驗(yàn)和信息轉(zhuǎn)化為生產(chǎn)力
- 15架起結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)之間的橋梁(AMT 唐曉輝 編譯)
- 16美公司推出下一代網(wǎng)絡(luò)服務(wù)工具包
- 17用Perl和XML輕松開(kāi)發(fā)多種界面的Web服務(wù)
- 18論文:信息系統(tǒng)開(kāi)發(fā)過(guò)程中的上海OA(By AMT 宋亮)
- 19證據(jù)顯示微軟曾阻礙Sun參加網(wǎng)絡(luò)服務(wù)標(biāo)準(zhǔn)組織
- 20Web服務(wù)之路越走越亮
- 21e信 知識(shí)生產(chǎn)新生態(tài)
- 22論文:知識(shí)型企業(yè)的上海OA策略(By AMT 宋亮)
- 23上海OA日趨重要
- 24聯(lián)合國(guó)《2003 年電子商務(wù)與發(fā)展報(bào)告》
- 25泛普(上海)OA績(jī)效有以下特點(diǎn)
- 26上海OA和信息技術(shù)有什么關(guān)系?(by AMT 仲英豪編譯)
- 27Sun四處游說(shuō) 要加入WS-I組織董事會(huì)
- 28OA辦公軟件系統(tǒng)中的工作“民意調(diào)查”很強(qiáng)大
- 29麥肯錫電子商務(wù)論叢-讓老百姓輕松上網(wǎng)洽公,免再苦苦排隊(duì)等候
- 30[經(jīng)典] 如何做好上海OA實(shí)施這道大餐?(AMT 孔祥云、徐家俊、孟凡強(qiáng))
成都公司:成都市成華區(qū)建設(shè)南路160號(hào)1層9號(hào)
重慶公司:重慶市江北區(qū)紅旗河溝華創(chuàng)商務(wù)大廈18樓
版權(quán)所有:泛普軟件 渝ICP備14008431號(hào)-2 渝公網(wǎng)安備50011202501700號(hào) 咨詢電話:400-8352-114