iNeo

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            30 Posts :: 8 Stories :: 2 Comments :: 0 Trackbacks

          #


            摘 要:簡要介紹了一種通用的,動態(tài)樹型結(jié)構(gòu)的實現(xiàn)方案,該方案基于Asynchronous JavaScript and XML,結(jié)合Struts框架設(shè)計實現(xiàn)了結(jié)構(gòu)清晰、擴展性良好的多層架構(gòu),數(shù)據(jù)存儲于數(shù)據(jù)庫,結(jié)合XML描述樹的節(jié)點信息,使得任何按預(yù)定的XML文檔描述的信息都可以通過動態(tài)樹來展現(xiàn)。

            關(guān)鍵詞:MVC模式;Ajax;樹型結(jié)構(gòu);字典序

            樹型結(jié)構(gòu)是一類應(yīng)用非常廣泛的數(shù)據(jù)結(jié)構(gòu)。人類社會中宗族的族譜和現(xiàn)代企業(yè)的組織形式都是樹型結(jié)構(gòu)。在計算機領(lǐng)域中,文件系統(tǒng)中文件的管理結(jié)構(gòu)、存儲器管理中的頁表、數(shù)據(jù)庫中的索引等也都是樹型結(jié)構(gòu)。隨著Internet的飛速發(fā)展,樹型結(jié)構(gòu)在瀏覽器/服務(wù)器(Browser/Server,簡稱B/S)應(yīng)用系統(tǒng)的應(yīng)用也越來越廣泛。

            目前,在互聯(lián)網(wǎng)上廣泛存在、應(yīng)用的樹型結(jié)構(gòu)一般分為兩種:靜態(tài)和動態(tài)結(jié)構(gòu)。靜態(tài)結(jié)構(gòu)存在最多、實現(xiàn)簡單,但是靜態(tài)導(dǎo)致不能改變樹的結(jié)構(gòu)和內(nèi)容,無法反映樹的節(jié)點信息的變化;而實現(xiàn)相對復(fù)雜的動態(tài)構(gòu)造樹,雖然可以動態(tài)增加、刪除、更新節(jié)點信息,但是大部分不能直接拖放節(jié)點來改變樹的結(jié)構(gòu)以及節(jié)點間的次序,并且反復(fù)刷新整個頁面,給用戶維護帶來了許多不便。本文提出了一種基于Ajax (Asynchronous JavaScript and XML)通用的、動態(tài)加載節(jié)點的解決方案。實現(xiàn)上采用J2EE多層架構(gòu),樹節(jié)點的描述信息采用數(shù)據(jù)庫存儲,以可擴展標記語言(eXtensible Markup Language,簡稱XML)展現(xiàn)給JavaScript解析,支持無刷新地增加、刪除、更新節(jié)點信息,以及拖放節(jié)點來改變樹的結(jié)構(gòu)和節(jié)點間的次序。文中第1部分簡要介紹了Ajax技術(shù);第2部分詳細介紹了該方案的技術(shù)實現(xiàn)過程;第3部分分析了該方案的效率。

            1、Ajax簡介

            Ajax概念的最早提出者Jesse James Garrett認為:Ajax并不是一門新的語言或技術(shù),它實際上是幾項技術(shù)按一定的方式組合在共同的協(xié)作中發(fā)揮各自的作用,它包括:

            ·使用擴展超媒體標記語言(eXtended Hypertext Markup Language,簡稱XHTML)和級聯(lián)樣式單(Cascading Style Sheet,簡稱CSS)標準化呈現(xiàn);

            ·使用文檔對象模型(Document Object Model,簡稱DOM)實現(xiàn)動態(tài)顯示和交互;

            ·使用可擴展標記語言(eXtensible Markup Language,簡稱XML)和可擴展樣式表轉(zhuǎn)換(eXtensible Stylesheet Language Transformation,簡稱XSLT)進行數(shù)據(jù)交換與處理;

            ·使用XMLHTTP組件XMLHttpRequest對象進行異步數(shù)據(jù)讀取;

            ·最后用JavaScript綁定和處理所有數(shù)據(jù)。

            Ajax的工作原理如圖1所示,它相當(dāng)于在用戶和服務(wù)器之間加了一個中間層,使用戶操作與服務(wù)器響應(yīng)異步化。并不是所有的用戶請求都提交給服務(wù)器,像— 些數(shù)據(jù)驗證和數(shù)據(jù)處理等都交給Ajax引擎處理,只有確定需要從服務(wù)器讀取新數(shù)據(jù)時再由Ajax引擎代為向服務(wù)器提交請求。這樣就把一些服務(wù)器負擔(dān)的工作轉(zhuǎn)嫁到客戶端,利用客戶端閑置的處理能力來處理,減輕服務(wù)器和帶寬的負擔(dān),從而達到節(jié)約ISP的空間及帶寬租用成本的目的。


          圖 1 未使用Ajax(a)和使用Ajax(b)的web應(yīng)用比較

            2、總體設(shè)計方案

            傳統(tǒng)的服務(wù)器程序采用Model 1開發(fā)模型,通常將業(yè)務(wù)邏輯、服務(wù)器端處理過程和HTML代碼集中在一起表示,快速完成應(yīng)用開發(fā)。Model 1 在小規(guī)模應(yīng)用開發(fā)時優(yōu)勢明顯,但是應(yīng)用實現(xiàn)一般是基于過程的,一組服務(wù)器頁面實現(xiàn)一個流程,如果流程改動將導(dǎo)致多個地方修改,非常不利于應(yīng)用的擴展和更新。此外業(yè)務(wù)邏輯和表示邏輯混合在服務(wù)器頁面中,耦合緊密,無法模塊化,導(dǎo)致代碼無法復(fù)用。

            Model 2則解決了這些問題,它是面向?qū)ο蟮腗VC模式(Model-View-Controller,模型-視圖-控制器)在Web開發(fā)中的應(yīng)用,Model表示應(yīng)用的業(yè)務(wù)邏輯,View是應(yīng)用的表示層頁面,Controller是提供應(yīng)用的處理過程控制。通過這種MVC設(shè)計模式把應(yīng)用邏輯,處理過程和顯示邏輯劃分成不同的組件、模塊實現(xiàn),組件間可以進行交互和重用。

            本方案是采用J2EE的多層架構(gòu),設(shè)計時結(jié)合Struts框架將表示層、業(yè)務(wù)邏輯層和數(shù)據(jù)層劃分成不同的模塊。表示層專注于樹的外觀顯示,業(yè)務(wù)邏輯層為服務(wù)器端處理程序,處理樹的生成、變化,為減少耦合性,該程序全部模塊化實現(xiàn),不在表示頁面嵌入服務(wù)器程序;模型層是數(shù)據(jù)的存儲和表示。下面分別介紹各層實現(xiàn)。

          原文鏈接:http://www.7dspace.com/doc/44/0512/2005122906292220003.htm
          posted @ 2005-12-30 08:28 只牽這只狗 閱讀(311) | 評論 (0)編輯 收藏

          Google工程師詳述Google的搜索結(jié)果排列算法
           

          本文作者馬特-卡茲(Matt Cutts)是Google公司品質(zhì)管理部門的軟件工程師。他的工作主要是給好的網(wǎng)站評定等級,并負責(zé)開發(fā)阻止虛假或垃圾網(wǎng)站出現(xiàn)在Google搜索結(jié)果上的技術(shù)。

          圖書館管理員們提出最多的問題之一是:“對于什么樣的結(jié)果應(yīng)該位于搜索列表的最上方,Google是如何選擇的?”現(xiàn)在品質(zhì)工程師馬特-卡茲介紹了快速入門的知識,解釋了Google是如何在網(wǎng)上爬行和索引,以及如何評定搜索結(jié)果等級的。馬特也向?qū)W校圖書館管理員提出建議,告訴他們?nèi)绾屋o導(dǎo)學(xué)生。

          爬行和索引

          在你瀏覽包含了Google搜索結(jié)果的網(wǎng)頁之前,要發(fā)生很多事情。首先是在萬維網(wǎng)數(shù)以十億計的網(wǎng)頁上爬行和索引,這個工作是由Googlebot完成的,它負責(zé)與全球的網(wǎng)絡(luò)服務(wù)器連接以收集文件。爬行不是真的在網(wǎng)上漫游,而是訪問網(wǎng)絡(luò)服務(wù)器返回到一個特定的網(wǎng)頁上,接著掃描該網(wǎng)頁建立超鏈接并為每一個網(wǎng)頁編上號碼。爬行可收集大量的文件,但這些文件還不能直接用于搜索。

          如果沒有索引,在你想查詢?nèi)纭癱ivil war”(南北戰(zhàn)爭)等內(nèi)容時,Google的服務(wù)器將不得不在你每次搜索時閱讀每一份文件的內(nèi)容。因此第二個步驟是要建立一個索引,這樣就需要“轉(zhuǎn)換” 爬行所獲得的數(shù)據(jù)。為了不必在每一份文件上掃描每一個單詞,就需要在數(shù)據(jù)上做些文章,以便顯示包含了特定單詞的所有文件。例如,假設(shè)單詞“civil”在編號為3、8、22、56、68和92的文件上出現(xiàn)過,而單詞“war”出現(xiàn)編號為2、8、15、22、68和77的文件上。

          一旦建立了索引,就開始對文件進行等級評定并確定它們的相關(guān)性。假如某個人上Google搜索并輸入“civil war”,為呈現(xiàn)和評價搜索結(jié)果需要做兩件事:一是查找包含了用戶提問的網(wǎng)頁;二是按照相關(guān)性排定匹配網(wǎng)頁的位置。Google已經(jīng)開發(fā)出一個有趣的技術(shù)可加速第一步驟的過程:不是將所有索引存儲在一臺電腦上,而是使用數(shù)百臺電腦做這種工作。由于任務(wù)被分配到很多電腦上,使得查詢答案更為迅速。

          為更加形象地描述這個過程,可以設(shè)想下一本30頁厚書的索引。如果一個人在索引中查找數(shù)頁的信息,那么每一次搜索都至少需要花幾秒鐘的時間;但如果你將索引的每一頁分給不同的人去查找呢?三十個人分別查找索引的不同部分,要比一個人獨自查找快的多。同樣,Google也是將數(shù)據(jù)分配到各臺電腦上以便可以更快地查找文件。

          如何查找包含了用戶提問的網(wǎng)頁?讓我們返回到上面舉的“civil war”例子。單詞“civil”在編號為3、8、22、56、68和92的文件上,單詞“war”在編號為2、8、15、22、68和77的文件上,我們可以在網(wǎng)頁上顯示文件并尋找包含兩個單詞的文件(從下表中可以看出是8、22和68號文件)。

          單詞civil 3 8 22 56 68 92

          單詞war 2 8 15 22 68 77

          兩個單詞都出現(xiàn) 8 22 68

          包含了一個單詞的文件列表被稱為“文件標識列表”,查找包含兩個單詞的文件被稱為“文件標識列表的交集”。

          評定搜索結(jié)果

          有了包含用戶提問的網(wǎng)頁后,就該按照相關(guān)性評定網(wǎng)頁了。Google使用了很多技術(shù),其中 PageRank算法是最有名的。PageRank評定的是兩種事情:從網(wǎng)站到某一網(wǎng)頁有多少個鏈接,提供鏈接的網(wǎng)站的排名。使用PageRank,來自 CNN和紐約時報網(wǎng)站的鏈接的價值,是很多不太有名網(wǎng)站的兩倍。

          除了PageRank外Google還使用了很多其他技術(shù),例如一份文件所包含的 “civil”和“war”兩個單詞靠的很近,就比只使用了“war”單詞的包含“Revolutionary War”(獨立戰(zhàn)爭)的文件相關(guān)性要大的多。另外在題目中出現(xiàn)了“civil war”的網(wǎng)頁,它的相關(guān)性就比題目為“19th Century American Clothing”(19世紀的美國服裝)要重要的多。同樣如果“civil war”在網(wǎng)頁上出現(xiàn)了數(shù)次,比出現(xiàn)一次的網(wǎng)頁要相關(guān)的多。

          Google的目的是要找到知名度和相關(guān)性都大的網(wǎng)頁。如果兩個網(wǎng)頁出現(xiàn)匹配提問的信息數(shù)量幾乎一樣,我們常常會選擇更有名網(wǎng)站的鏈接。但如果其他方面表明一個網(wǎng)頁更為相關(guān),也會選擇更少鏈接或更低排名的網(wǎng)頁。例如,一個網(wǎng)頁全篇都是講“南北戰(zhàn)爭”的內(nèi)容,會比只是略微提到“南北戰(zhàn)爭”的網(wǎng)頁更為有用,即使這個網(wǎng)頁是出現(xiàn)不太有名的網(wǎng)站上。一旦我們有了文件的列表和分值,就會選擇最高分值、最匹配的文件。

          Google從包含了提問單詞的每一份文件中提取幾句話作為摘要顯示,接著將排好的URLs和摘要顯示在搜索結(jié)果上。正如你所知道的運行一個搜索器需要大量的計算資源。每一次搜索需要500臺以上的電腦一起工作,搜索的時間還不到半秒鐘。



          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=559502

          posted @ 2005-12-23 14:43 只牽這只狗 閱讀(213) | 評論 (0)編輯 收藏

          快圣誕晚會了,決定出個小節(jié)目——準備“嗷嗷”一下,呵.......終于有了點快樂的氣氛.....

          posted @ 2005-12-22 10:27 只牽這只狗 閱讀(197) | 評論 (0)編輯 收藏

               摘要:    觀察家模式是一個事件通知模式,被觀察者發(fā)生某個事件,或者狀態(tài)發(fā)生某個變化,就通知觀察者,這樣觀察者就能采取適當(dāng)?shù)男袆印O旅嫖乙砸粋€簡單的例子來說明一下這個模式的應(yīng)用。 我們都知道,蜜蜂是勤勞的精靈,它總是四處采蜜。只要花朵的花瓣一張開,她就飛上去采蜜。我們輕易就能想到,在這里,蜜蜂應(yīng)該是一個觀察者,而花朵是一個被觀察者。只要花朵發(fā)生花瓣張開事件,就通知了觀...  閱讀全文
          posted @ 2005-12-09 16:26 只牽這只狗 閱讀(345) | 評論 (0)編輯 收藏

          今天測試時出的一個錯誤,數(shù)據(jù)庫中一個表的說明欄位值全部成了“ui8ll/”,但卻無法再現(xiàn)。很郁悶,搞了半天查不出什么原因。應(yīng)該是編碼格式出現(xiàn)異常,但什么原因會突然造成編碼異常呢?且把整個這一欄的值全都變了而其他欄位卻正常?是數(shù)據(jù)庫的原因還是程序原因?
          google一下“ui8ll/”,沒有資料!

          JSP編碼:
          <%@ page contentType = "text/html;charset=GBK"%>
          database是DB2 欄位Type是varchar

          到底是什么原因呢?

          posted @ 2005-12-09 11:29 只牽這只狗 閱讀(196) | 評論 (0)編輯 收藏

          xml(可擴展標記語言)看起來可能像某種w3c標準——現(xiàn)在沒有什么實際影響,即使以后能派上用場,也是很久以后的事。但實際上,它現(xiàn)在已經(jīng)得到了應(yīng)用。所以,不要等到xml已被加進了你最喜愛的html編輯器中才開始使用它。它現(xiàn)在就可以解決各種內(nèi)部問題和b2b系統(tǒng)問題。

          在sparks.com,我們使用xml來標準化從java對象到html數(shù)據(jù)顯示等不同系統(tǒng)之間的數(shù)據(jù)表示。

          特別需要指出的是,我們發(fā)現(xiàn),只要以非常基本的xml結(jié)構(gòu)來實現(xiàn)標準化,就可以更容易地共享和操作數(shù)據(jù)。在這一過程中,我們發(fā)現(xiàn)了使用xml的很多有效方法。下面詳細介紹我們現(xiàn)在的應(yīng)用情況。

          標準化
          在使用xml之前,建立與你要使用的信息不同的xml數(shù)據(jù)格式。

          生成動態(tài)xml
          從數(shù)據(jù)庫中生成html并不新鮮,但生成xml卻很新鮮。這里我們介紹具體的生成步驟。

          用xsl作為模板語言
          xsl(可擴展樣式表語言)是定義xml數(shù)據(jù)顯示格式的好方法,如果寫成幾個靜態(tài)模板會更有效。

          生成html
          xml加上xsl就等于html。這聽起來似乎不對,但用戶所見的我們的html頁面其實就是xml和xsl共同產(chǎn)生的效果。


          一、標準化

          xml的能力來自于它的靈活性。但不幸的是,它有時太靈活了,以至于你會面對一個空白的頁面,發(fā)愁該怎么解決問題。

          在任何xml的項目中,第一步工作都是創(chuàng)建標準的數(shù)據(jù)格式。為此你要作出以下決定:

          ? 要涉及哪些數(shù)據(jù)
          ? 是否要使用dtd(文件類型定義)
          ? 是否要使用dom(文檔對象模型)或sax(xml的簡化api)解析

          確定數(shù)據(jù):
          因為沒有標準的xml格式,開發(fā)者可以自由地開發(fā)自己的格式。然而,如果你的格式只能被一個應(yīng)用程序識別,那么你只能運行這個程序來使用該格式。如果還有其他程序也能讀懂你的xml格式,那顯然會更有幫助。如果某個xml格式被修改,則使用它的系統(tǒng)可能也需要被修改,所以你應(yīng)該建立盡可能完整的格式。因為大多數(shù)系統(tǒng)忽略它們無法識別的標簽,所以改變一個xml格式的最安全的方法是添加標簽,而不是修改標簽。

          單擊此處查看xml數(shù)據(jù)格式實例

          在sparks.com,我們查看了不同的產(chǎn)品展示需要的所有產(chǎn)品數(shù)據(jù)。盡管并不是所有的頁面都使用全部數(shù)據(jù),但我們還是由此開發(fā)出適用于所有數(shù)據(jù)的非常完整的xml數(shù)據(jù)格式。例如,我們的產(chǎn)品明細信息頁面顯示的數(shù)據(jù)要比產(chǎn)品瀏覽頁面多。然而,我們在這兩種情況下仍然使用相同的數(shù)據(jù)格式,因為每個頁面的xsl模板都只使用它所需要的字段。

          是否使用dtd
          在sparks.com,我們使用組織良好的xml,而不使用僅僅是正確的xml,因為前者不需要dtd。dtd在用戶點擊和看到頁面之間加入了一個處理層。我們發(fā)現(xiàn)這一層需要太多的處理。當(dāng)然,在以xml格式與其他公司通信時,使用dtd還是很不錯的。因為dtd能在發(fā)送和接受時能保證數(shù)據(jù)結(jié)構(gòu)正確。

          選擇解析引擎
          現(xiàn)在,可以使用的解析引擎有好幾個。選擇哪一個幾乎完全取決于你的應(yīng)用需要。如果你決定使用dtd,那么這個解析引擎必須能使你的xml被dtd驗證。你可以將驗證另放到一個進程中,但那樣會影響性能。

          sax和dom是兩個基本的解析模型。sax基于事件,所以在xml被解析時,事件被發(fā)送給引擎。接下來,事件與輸出文件同步。dom解析引擎為動態(tài)xml數(shù)據(jù)和xsl樣式表建立層次樹狀結(jié)構(gòu)。通過隨機訪問dom樹,可以提供xml數(shù)據(jù),就象由xsl樣式表來決定一樣。sax模型上的爭論主要集中于對dom結(jié)構(gòu)的內(nèi)存降低過度和加快xsl樣式表解析時間縮短方面。

          然而,我們發(fā)現(xiàn)使用sax的很多系統(tǒng)并沒有充分發(fā)揮它的能力。這些系統(tǒng)用它來建立dom結(jié)構(gòu)并通過dom結(jié)構(gòu)來發(fā)送事件。用這種方法,在任何xml處理之前必須從樣式表中建立dom,所以性能會下降。

          二、生成動態(tài)xml

          一旦建立了xml格式,我們需要一種能夠?qū)⑵鋸臄?shù)據(jù)庫中動態(tài)移植的方法。

          生成xml文檔相對來說比較簡單,因為它只需要一個可以處理字符串的系統(tǒng)。我們建立了一個使用java servlet、enterprise javabean server、jdbc和rdbms(關(guān)系型數(shù)據(jù)庫管理系統(tǒng))的系統(tǒng)。

          ? servlet通過把生成xml文檔的任務(wù)交給enterprise javabean (ejb)來處理產(chǎn)品信息請求。
          ? ejb使用jdbc從數(shù)據(jù)庫里查詢所需的產(chǎn)品詳細信息。
          ? ejb生成xml文件并把它傳遞給servlet。
          ? servlet調(diào)用解析引擎,從xml文件和靜態(tài)的xsl樣式表中創(chuàng)建html輸出。

          (有關(guān)xsl應(yīng)用的其他信息,請參閱用xsl作為模板語言。)

          生成xml的例子
          在java中創(chuàng)建xml文檔字符串的真正代碼可以分成幾個方法和類。

          啟動xml生成過程的代碼放在ejb方法里。這一實例會立即創(chuàng)建一個stringbuffer,以便存儲生成的xml字符串。

          stringbuffer xml = new stringbuffer();
          xml.append(xmlutils.begindocument("/browse_find/browse.xsl", "browse", request));
          xml.append(product.toxml());
          xml.append(xmlutils.enddocument("browse");
          out.print(xml.tostring());


          后面的三個xml.append()變元本身就是對其他方法的調(diào)用。
          產(chǎn)生文件頭
          第一個附加方法調(diào)用xmlutils類來產(chǎn)生xml文件頭。我們的java servlet中的代碼如下:

          public static string begindocument(string stylesheet, string page)
          {
              stringbuffer xml = new stringbuffer();
              xml.append("\n")
              .append("    .append(stylesheet).append("\"")
              .append(" type =\"text/xsl\"?>\n");
            xml.append("<").append(page).append(">\n");
            return xml.tostring();
          }

          這段代碼生成了xml文件頭。標簽把本文件定義為支持1.0版本的xml文件。第二行代碼指向用以顯示數(shù)據(jù)的正確樣式表的位置。最后包括進去的是項級標簽(本實例中為)。在文件末尾,只有標簽需要被關(guān)閉。

          填入產(chǎn)品信息
          完成了文件頭后,控制方法會調(diào)用java對象來產(chǎn)生它的xml。本例中調(diào)用的是product對象。product對象使用兩個方法來產(chǎn)生它的xml表示。第一個方法toxml()通過產(chǎn)生標簽來建立product節(jié)點。然后它會調(diào)用internalxml(),這樣就能提供產(chǎn)品xml所需的內(nèi)容。internalxml()是一系列的stringbuffer.append()調(diào)用。stringbuffer也被轉(zhuǎn)換成字符串并返回給控制方法。
          public string toxml()
              {
              stringbuffer xml = new stringbuffer("\n");
              xml.append(internalxml());
              xml.append("
          \n");
              return xml.tostring();
              }

          public string internalxml()
              {
              stringbuffer xml = new
              stringbuffer("\t")
                  .append(producttype).append("\n");
              xml.append("\t").append(idvalue.trim())
                  .append("\n");
              xml.append("\t").append(idname.trim())
                  .append("\n");
              xml.append("\t").append(page.trim())
                  .append("\n");
          厖?
                xml.append("\t").append(amount).append("\n");
              xml.append("\t").append(vendor).append("\n");
              xml.append("\t\n");
              xml.append("\t").append(pubdesc).append("\n");
              xml.append("\t").append(vendesc).append("\n";
          厖?
              return xml.tostring();
          }


          關(guān)閉文件
          最后,xmlutils.enddocument()方法被調(diào)用。這個調(diào)用關(guān)閉xml標簽(本例中為),并最終完成架構(gòu)好的xml文件。來自控制方法的整個stringbuffer也轉(zhuǎn)換成字符串,并返回給處理最初http請求的servlet。

          三、用xsl作為模板語言

          為了得到html輸出,我們把生成的xml文件和控制xml數(shù)據(jù)如何表示的xsl模板相結(jié)合。我們的xsl模板由精心組織的xsl和html標簽組成。

          開始建模板
          我們的xsl模板開始部分與下面這段代碼類似。第一行代碼為必需代碼,將本文件定義為xsl樣式表。xmlns:xsl=屬性引用本文件所使用的xml名稱空間,而version=屬性則定義名稱空間的版本號。在文件的末尾,我們關(guān)閉標簽。

          開始的第二行代碼確定了xsl模板的模式。match屬性是必需的,在這里指向xml標簽。在我們的系統(tǒng)里,標簽里包含 標簽,這使得xsl模板可以訪問嵌在標簽內(nèi)的產(chǎn)品信息。我們又一次必須在文件末尾關(guān)閉標簽。

          接下來,我們來看一看組織良好的html。由于它將被xml解析引擎處理,所以必須符合組織良好的xml的所有規(guī)則。從本質(zhì)上來講,這意味著所有的開始標簽必須有對應(yīng)的結(jié)束標簽。例如,通常不被結(jié)束的

          標簽,必須用

          關(guān)閉。
          http://www.w3.org/1999/xsl/transform"
          version="1.0">?br>

          在模板的主體內(nèi),有很多xsl標簽被用于為數(shù)據(jù)表示提供邏輯。下面解釋兩個常用的標簽。
          choose
          標簽類似于傳統(tǒng)編程語言中if-then-else結(jié)構(gòu)的開始部分。在xsl中,choose標簽表示在代碼進入的部分中,賦值將觸發(fā)動作的發(fā)生。擁有賦值屬性的標簽跟在choose標簽后面。如果賦值是正確的,位于的開始和結(jié)束標簽之間的內(nèi)容將被使用。如果賦值錯誤,就使用的開始和結(jié)束標簽之間的內(nèi)容。整個部分用來結(jié)束。

          在這個例子里,when標簽會為quantity標簽檢查xml。如果quantity標簽里含有值為真的error屬性,quantity標簽將會顯示列在下面的表格單元。如果屬性的值不為真,xsl將會顯示otherwise標簽間的內(nèi)容。在下面的實例里,如果error屬性不真,則什么都不會被顯示。

          posted @ 2005-12-07 11:47 只牽這只狗 閱讀(234) | 評論 (0)編輯 收藏

          java.util 中的集合類包含 Java 中某些最常用的類。 最常用的集合類是 List 和 Map。 List 的具體實現(xiàn)包括 ArrayList 和 Vector,它們是可變大小的列表,比較適合構(gòu)建、存儲和操作任何類型對象的元素列表。 List 適用于按數(shù)值索引訪問元素的情形。

          Map 提供了一個更通用的元素存儲方法。 Map 集合類用于存儲元素對(稱作“鍵”和“值”),其中每個鍵映射到一個值。 從概念上而言,您可以將 List 看作是具有數(shù)值鍵的 Map。 而實際上,除了 List 和 Map 都在定義 java.util 中外,兩者并沒有直接的聯(lián)系。本文將著重介紹核心 Java 發(fā)行套件中附帶的 Map,同時還將介紹如何采用或?qū)崿F(xiàn)更適用于您應(yīng)用程序特定數(shù)據(jù)的專用 Map。

          了解 Map 接口和方法

          Java 核心類中有很多預(yù)定義的 Map 類。 在介紹具體實現(xiàn)之前,我們先介紹一下 Map 接口本身,以便了解所有實現(xiàn)的共同點。 Map 接口定義了四種類型的方法,每個 Map 都包含這些方法。 下面,我們從兩個普通的方法(表 1)開始對這些方法加以介紹。

          表 1: 覆蓋的方法。 我們將這 Object 的這兩個方法覆蓋,以正確比較 Map 對象的等價性。 equals(Object o) 比較指定對象與此 Map 的等價性
          hashCode() 返回此 Map 的哈希碼



          Map 構(gòu)建

          Map 定義了幾個用于插入和刪除元素的變換方法(表 2)。

          表 2: Map 更新方法: 可以更改 Map 內(nèi)容。 clear() 從 Map 中刪除所有映射
          remove(Object key) 從 Map 中刪除鍵和關(guān)聯(lián)的值
          put(Object key, Object value) 將指定值與指定鍵相關(guān)聯(lián)
          clear() 從 Map 中刪除所有映射
          putAll(Map t) 將指定 Map 中的所有映射復(fù)制到此 map



          盡管您可能注意到,縱然假設(shè)忽略構(gòu)建一個需要傳遞給 putAll() 的 Map 的開銷,使用 putAll() 通常也并不比使用大量的 put() 調(diào)用更有效率,但 putAll() 的存在一點也不稀奇。 這是因為,putAll() 除了迭代 put() 所執(zhí)行的將每個鍵值對添加到 Map 的算法以外,還需要迭代所傳遞的 Map 的元素。 但應(yīng)注意,putAll() 在添加所有元素之前可以正確調(diào)整 Map 的大小,因此如果您未親自調(diào)整 Map 的大小(我們將對此進行簡單介紹),則 putAll() 可能比預(yù)期的更有效。

          查看 Map

          迭代 Map 中的元素不存在直接了當(dāng)?shù)姆椒ā?如果要查詢某個 Map 以了解其哪些元素滿足特定查詢,或如果要迭代其所有元素(無論原因如何),則您首先需要獲取該 Map 的“視圖”。 有三種可能的視圖(參見表 3)

          所有鍵值對 — 參見 entrySet()
          所有鍵 — 參見 keySet()
          所有值 — 參見 values()

          前兩個視圖均返回 Set 對象,第三個視圖返回 Collection 對象。 就這兩種情況而言,問題到這里并沒有結(jié)束,這是因為您無法直接迭代 Collection 對象或 Set 對象。要進行迭代,您必須獲得一個 Iterator 對象。 因此,要迭代 Map 的元素,必須進行比較煩瑣的編碼


          Iterator keyValuePairs = aMap.entrySet().iterator();
          Iterator keys = aMap.keySet().iterator();
          Iterator values = aMap.values().iterator();


          值得注意的是,這些對象(Set、Collection 和 Iterator)實際上是基礎(chǔ) Map 的視圖,而不是包含所有元素的副本。 這使它們的使用效率很高。 另一方面,Collection 或 Set 對象的 toArray() 方法卻創(chuàng)建包含 Map 所有元素的數(shù)組對象,因此除了確實需要使用數(shù)組中元素的情形外,其效率并不高。

          我運行了一個小測試(隨附文件中的 Test1),該測試使用了 HashMap,并使用以下兩種方法對迭代 Map 元素的開銷進行了比較:


          int mapsize = aMap.size();

          Iterator keyValuePairs1 = aMap.entrySet().iterator();
          for (int i = 0; i < mapsize; i++)
          {
          Map.Entry entry = (Map.Entry) keyValuePairs1.next();
          Object key = entry.getKey();
          Object value = entry.getValue();
          ...
          }

          Object[] keyValuePairs2 = aMap.entrySet().toArray();
          for (int i = 0; i < rem; i++) {
          {
          Map.Entry entry = (Map.Entry) keyValuePairs2[i];
          Object key = entry.getKey();


          Object value = entry.getValue();
          ...
          }


          此測試使用了兩種測量方法: 一種是測量迭代元素的時間,另一種測量使用 toArray 調(diào)用創(chuàng)建數(shù)組的其他開銷。 第一種方法(忽略創(chuàng)建數(shù)組所需的時間)表明,使用已從 toArray 調(diào)用中創(chuàng)建的數(shù)組迭代元素的速度要比使用 Iterator 的速度大約快 30%-60%。 但如果將使用 toArray 方法創(chuàng)建數(shù)組的開銷包含在內(nèi),則使用 Iterator 實際上要快 10%-20%。 因此,如果由于某種原因要創(chuàng)建一個集合元素的數(shù)組而非迭代這些元素,則應(yīng)使用該數(shù)組迭代元素。 但如果您不需要此中間數(shù)組,則不要創(chuàng)建它,而是使用 Iterator 迭代元素。

          表 3: 返回視圖的 Map 方法: 使用這些方法返回的對象,您可以遍歷 Map 的元素,還可以刪除 Map 中的元素。 entrySet() 返回 Map 中所包含映射的 Set 視圖。 Set 中的每個元素都是一個 Map.Entry 對象,可以使用 getKey() 和 getValue() 方法(還有一個 setValue() 方法)訪問后者的鍵元素和值元素
          keySet() 返回 Map 中所包含鍵的 Set 視圖。 刪除 Set 中的元素還將刪除 Map 中相應(yīng)的映射(鍵和值)
          values() 返回 map 中所包含值的 Collection 視圖。 刪除 Collection 中的元素還將刪除 Map 中相應(yīng)的映射(鍵和值)



          訪問元素

          表 4 中列出了 Map 訪問方法。Map 通常適合按鍵(而非按值)進行訪問。 Map 定義中沒有規(guī)定這肯定是真的,但通常您可以期望這是真的。 例如,您可以期望 containsKey() 方法與 get() 方法一樣快。 另一方面,containsValue() 方法很可能需要掃描 Map 中的值,因此它的速度可能比較慢。

          表 4: Map 訪問和測試方法: 這些方法檢索有關(guān) Map 內(nèi)容的信息但不更改 Map 內(nèi)容。 get(Object key) 返回與指定鍵關(guān)聯(lián)的值
          containsKey(Object key) 如果 Map 包含指定鍵的映射,則返回 true
          containsValue(Object value) 如果此 Map 將一個或多個鍵映射到指定值,則返回 true
          isEmpty() 如果 Map 不包含鍵-值映射,則返回 true
          size() 返回 Map 中的鍵-值映射的數(shù)目



          對使用 containsKey() 和 containsValue() 遍歷 HashMap 中所有元素所需時間的測試表明,containsValue() 所需的時間要長很多。 實際上要長幾個數(shù)量級! (參見圖 1 和圖 2,以及隨附文件中的 Test2)。 因此,如果 containsValue() 是應(yīng)用程序中的性能問題,它將很快顯現(xiàn)出來,并可以通過監(jiān)測您的應(yīng)用程序輕松地將其識別。 這種情況下,我相信您能夠想出一個有效的替換方法來實現(xiàn) containsValue() 提供的等效功能。 但如果想不出辦法,則一個可行的解決方案是再創(chuàng)建一個 Map,并將第一個 Map 的所有值作為鍵。 這樣,第一個 Map 上的 containsValue() 將成為第二個 Map 上更有效的 containsKey()。


          圖 1: 使用 JDeveloper 創(chuàng)建并運行 Map 測試類




          圖 2: 在 JDeveloper 中使用執(zhí)行監(jiān)測器進行的性能監(jiān)測查出應(yīng)用程序中的瓶頸



          核心 Map

          Java 自帶了各種 Map 類。 這些 Map 類可歸為三種類型:


          通用 Map,用于在應(yīng)用程序中管理映射,通常在 java.util 程序包中實現(xiàn)
          HashMap
          Hashtable
          Properties
          LinkedHashMap
          IdentityHashMap
          TreeMap
          WeakHashMap
          ConcurrentHashMap
          專用 Map,您通常不必親自創(chuàng)建此類 Map,而是通過某些其他類對其進行訪問
          java.util.jar.Attributes
          javax.print.attribute.standard.PrinterStateReasons
          java.security.Provider
          java.awt.RenderingHints
          javax.swing.UIDefaults
          一個用于幫助實現(xiàn)您自己的 Map 類的抽象類
          AbstractMap

          內(nèi)部哈希: 哈希映射技術(shù)

          幾乎所有通用 Map 都使用哈希映射。 這是一種將元素映射到數(shù)組的非常簡單的機制,您應(yīng)了解哈希映射的工作原理,以便充分利用 Map。

          哈希映射結(jié)構(gòu)由一個存儲元素的內(nèi)部數(shù)組組成。 由于內(nèi)部采用數(shù)組存儲,因此必然存在一個用于確定任意鍵訪問數(shù)組的索引機制。 實際上,該機制需要提供一個小于數(shù)組大小的整數(shù)索引值。 該機制稱作哈希函數(shù)。 在 Java 基于哈希的 Map 中,哈希函數(shù)將對象轉(zhuǎn)換為一個適合內(nèi)部數(shù)組的整數(shù)。 您不必為尋找一個易于使用的哈希函數(shù)而大傷腦筋: 每個對象都包含一個返回整數(shù)值的 hashCode() 方法。 要將該值映射到數(shù)組,只需將其轉(zhuǎn)換為一個正值,然后在將該值除以數(shù)組大小后取余數(shù)即可。 以下是一個簡單的、適用于任何對象的 Java 哈希函數(shù)


          int hashvalue = Maths.abs(key.hashCode()) % table.length;


          (% 二進制運算符(稱作模)將左側(cè)的值除以右側(cè)的值,然后返回整數(shù)形式的余數(shù)。)

          實際上,在 1.4 版發(fā)布之前,這就是各種基于哈希的 Map 類所使用的哈希函數(shù)。 但如果您查看一下代碼,您將看到


          int hashvalue = (key.hashCode() & 0x7FFFFFFF) % table.length;


          它實際上是使用更快機制獲取正值的同一函數(shù)。 在 1.4 版中,HashMap 類實現(xiàn)使用一個不同且更復(fù)雜的哈希函數(shù),該函數(shù)基于 Doug Lea 的 util.concurrent 程序包(稍后我將更詳細地再次介紹 Doug Lea 的類)。


          圖 3: 哈希工作原理



          該圖介紹了哈希映射的基本原理,但我們還沒有對其進行詳細介紹。 我們的哈希函數(shù)將任意對象映射到一個數(shù)組位置,但如果兩個不同的鍵映射到相同的位置,情況將會如何? 這是一種必然發(fā)生的情況。 在哈希映射的術(shù)語中,這稱作沖突。 Map 處理這些沖突的方法是在索引位置處插入一個鏈接列表,并簡單地將元素添加到此鏈接列表。 因此,一個基于哈希的 Map 的基本 put() 方法可能如下所示


          public Object put(Object key, Object value) {
          //我們的內(nèi)部數(shù)組是一個 Entry 對象數(shù)組
          //Entry[] table;

          //獲取哈希碼,并映射到一個索引
          int hash = key.hashCode();
          int index = (hash & 0x7FFFFFFF) % table.length;

          //循環(huán)遍歷位于 table[index] 處的鏈接列表,以查明
          //我們是否擁有此鍵項 — 如果擁有,則覆蓋它
          for (Entry e = table[index] ; e != null ; e = e.next) {
          //必須檢查鍵是否相等,原因是不同的鍵對象
          //可能擁有相同的哈希
          if ((e.hash == hash) && e.key.equals(key)) {
          //這是相同鍵,覆蓋該值
          //并從該方法返回 old 值
          Object old = e.value;
          e.value = value;
          return old;
          }
          }

          //仍然在此處,因此它是一個新鍵,只需添加一個新 Entry
          //Entry 對象包含 key 對象、 value 對象、一個整型的 hash、
          //和一個指向列表中的下一個 Entry 的 next Entry

          //創(chuàng)建一個指向上一個列表開頭的新 Entry,
          //并將此新 Entry 插入表中
          Entry e = new Entry(hash, key, value, table[index]);
          table[index] = e;

          return null;
          }



          如果看一下各種基于哈希的 Map 的源代碼,您將發(fā)現(xiàn)這基本上就是它們的工作原理。 此外,還有一些需要進一步考慮的事項,如處理空鍵和值以及調(diào)整內(nèi)部數(shù)組。 此處定義的 put() 方法還包含相應(yīng) get() 的算法,這是因為插入包括搜索映射索引處的項以查明該鍵是否已經(jīng)存在。 (即 get() 方法與 put() 方法具有相同的算法,但 get() 不包含插入和覆蓋代碼。) 使用鏈接列表并不是解決沖突的唯一方法,某些哈希映射使用另一種“開放式尋址”方案,本文對其不予介紹。

          優(yōu)化 Hasmap

          如果哈希映射的內(nèi)部數(shù)組只包含一個元素,則所有項將映射到此數(shù)組位置,從而構(gòu)成一個較長的鏈接列表。 由于我們的更新和訪問使用了對鏈接列表的線性搜索,而這要比 Map 中的每個數(shù)組索引只包含一個對象的情形要慢得多,因此這樣做的效率很低。 訪問或更新鏈接列表的時間與列表的大小線性相關(guān),而使用哈希函數(shù)訪問或更新數(shù)組中的單個元素則與數(shù)組大小無關(guān) — 就漸進性質(zhì)(Big-O 表示法)而言,前者為 O(n),而后者為 O(1)。 因此,使用一個較大的數(shù)組而不是讓太多的項聚集在太少的數(shù)組位置中是有意義的。

          調(diào)整 Map 實現(xiàn)的大小

          在哈希術(shù)語中,內(nèi)部數(shù)組中的每個位置稱作“存儲桶”(bucket),而可用的存儲桶數(shù)(即內(nèi)部數(shù)組的大小)稱作容量 (capacity)。 為使 Map 對象有效地處理任意數(shù)目的項,Map 實現(xiàn)可以調(diào)整自身的大小。 但調(diào)整大小的開銷很大。 調(diào)整大小需要將所有元素重新插入到新數(shù)組中,這是因為不同的數(shù)組大小意味著對象現(xiàn)在映射到不同的索引值。 先前沖突的鍵可能不再沖突,而先前不沖突的其他鍵現(xiàn)在可能沖突。 這顯然表明,如果將 Map 調(diào)整得足夠大,則可以減少甚至不再需要重新調(diào)整大小,這很有可能顯著提高速度。

          使用 1.4.2 JVM 運行一個簡單的測試,即用大量的項(數(shù)目超過一百萬)填充 HashMap。 表 5 顯示了結(jié)果,并將所有時間標準化為已預(yù)先設(shè)置大小的服務(wù)器模式(關(guān)聯(lián)文件中的 Test3)。 對于已預(yù)先設(shè)置大小的 JVM,客戶端和服務(wù)器模式 JVM 運行時間幾乎相同(在放棄 JIT 編譯階段后)。 但使用 Map 的默認大小將引發(fā)多次調(diào)整大小操作,開銷很大,在服務(wù)器模式下要多用 50% 的時間,而在客戶端模式下幾乎要多用兩倍的時間!

          表 5: 填充已預(yù)先設(shè)置大小的 HashMap 與填充默認大小的 HashMap 所需時間的比較 客戶端模式 服務(wù)器模式
          預(yù)先設(shè)置的大小 100% 100%
          默認大小 294% 157%



          使用負載因子

          為確定何時調(diào)整大小,而不是對每個存儲桶中的鏈接列表的深度進行記數(shù),基于哈希的 Map 使用一個額外參數(shù)并粗略計算存儲桶的密度。 Map 在調(diào)整大小之前,使用名為“負載因子”的參數(shù)指示 Map 將承擔(dān)的“負載”量,即它的負載程度。 負載因子、項數(shù)(Map 大小)與容量之間的關(guān)系簡單明了:


          如果(負載因子)x(容量)>(Map 大小),則調(diào)整 Map 大小

          例如,如果默認負載因子為 0.75,默認容量為 11,則 11 x 0.75 = 8.25,該值向下取整為 8 個元素。 因此,如果將第 8 個項添加到此 Map,則該 Map 將自身的大小調(diào)整為一個更大的值。 相反,要計算避免調(diào)整大小所需的初始容量,用將要添加的項數(shù)除以負載因子,并向上取整,例如,


          對于負載因子為 0.75 的 100 個項,應(yīng)將容量設(shè)置為 100/0.75 = 133.33,并將結(jié)果向上取整為 134(或取整為 135 以使用奇數(shù))

          奇數(shù)個存儲桶使 map 能夠通過減少沖突數(shù)來提高執(zhí)行效率。 雖然我所做的測試(關(guān)聯(lián)文件中的Test4)并未表明質(zhì)數(shù)可以始終獲得更好的效率,但理想情形是容量取質(zhì)數(shù)。 1.4 版后的某些 Map(如 HashMap 和 LinkedHashMap,而非 Hashtable 或 IdentityHashMap)使用需要 2 的冪容量的哈希函數(shù),但下一個最高 2 的冪容量由這些 Map 計算,因此您不必親自計算。

          負載因子本身是空間和時間之間的調(diào)整折衷。 較小的負載因子將占用更多的空間,但將降低沖突的可能性,從而將加快訪問和更新的速度。 使用大于 0.75 的負載因子可能是不明智的,而使用大于 1.0 的負載因子肯定是不明知的,這是因為這必定會引發(fā)一次沖突。 使用小于 0.50 的負載因子好處并不大,但只要您有效地調(diào)整 Map 的大小,應(yīng)不會對小負載因子造成性能開銷,而只會造成內(nèi)存開銷。 但較小的負載因子將意味著如果您未預(yù)先調(diào)整 Map 的大小,則導(dǎo)致更頻繁的調(diào)整大小,從而降低性能,因此在調(diào)整負載因子時一定要注意這個問題。

          選擇適當(dāng)?shù)?Map

          應(yīng)使用哪種 Map? 它是否需要同步? 要獲得應(yīng)用程序的最佳性能,這可能是所面臨的兩個最重要的問題。 當(dāng)使用通用 Map 時,調(diào)整 Map 大小和選擇負載因子涵蓋了 Map 調(diào)整選項。

          以下是一個用于獲得最佳 Map 性能的簡單方法

          將您的所有 Map 變量聲明為 Map,而不是任何具體實現(xiàn),即不要聲明為 HashMap 或 Hashtable,或任何其他 Map 類實現(xiàn)。


          Map criticalMap = new HashMap(); //好

          HashMap criticalMap = new HashMap(); //差


          這使您能夠只更改一行代碼即可非常輕松地替換任何特定的 Map 實例。

          下載 Doug Lea 的 util.concurrent 程序包 (http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html)。 將 ConcurrentHashMap 用作默認 Map。 當(dāng)移植到 1.5 版時,將 java.util.concurrent.ConcurrentHashMap 用作您的默認 Map。 不要將 ConcurrentHashMap 包裝在同步的包裝器中,即使它將用于多個線程。 使用默認大小和負載因子。
          監(jiān)測您的應(yīng)用程序。 如果發(fā)現(xiàn)某個 Map 造成瓶頸,則分析造成瓶頸的原因,并部分或全部更改該 Map 的以下內(nèi)容: Map 類;Map 大小;負載因子;關(guān)鍵對象 equals() 方法實現(xiàn)。 專用的 Map 的基本上都需要特殊用途的定制 Map 實現(xiàn),否則通用 Map 將實現(xiàn)您所需的性能目標。

          Map 選擇

          也許您曾期望更復(fù)雜的考量,而這實際上是否顯得太容易? 好的,讓我們慢慢來。 首先,您應(yīng)使用哪種 Map? 答案很簡單: 不要為您的設(shè)計選擇任何特定的 Map,除非實際的設(shè)計需要指定一個特殊類型的 Map。 設(shè)計時通常不需要選擇具體的 Map 實現(xiàn)。 您可能知道自己需要一個 Map,但不知道使用哪種。 而這恰恰就是使用 Map 接口的意義所在。 直到需要時再選擇 Map 實現(xiàn) — 如果隨處使用“Map”聲明的變量,則更改應(yīng)用程序中任何特殊 Map 的 Map 實現(xiàn)只需要更改一行,這是一種開銷很少的調(diào)整選擇。 是否要使用默認的 Map 實現(xiàn)? 我很快將談到這個問題。

          同步 Map

          同步與否有何差別? (對于同步,您既可以使用同步的 Map,也可以使用 Collections.synchronizedMap() 將未同步的 Map 轉(zhuǎn)換為同步的 Map。 后者使用“同步的包裝器”)這是一個異常復(fù)雜的選擇,完全取決于您如何根據(jù)多線程并發(fā)訪問和更新使用 Map,同時還需要進行維護方面的考慮。 例如,如果您開始時未并發(fā)更新特定 Map,但它后來更改為并發(fā)更新,情況將如何? 在這種情況下,很容易在開始時使用一個未同步的 Map,并在后來向應(yīng)用程序中添加并發(fā)更新線程時忘記將此未同步的 Map 更改為同步的 Map。 這將使您的應(yīng)用程序容易崩潰(一種要確定和跟蹤的最糟糕的錯誤)。 但如果默認為同步,則將因隨之而來的可怕性能而序列化執(zhí)行多線程應(yīng)用程序。 看起來,我們需要某種決策樹來幫助我們正確選擇。

          Doug Lea 是紐約州立大學(xué)奧斯威戈分校計算機科學(xué)系的教授。 他創(chuàng)建了一組公共領(lǐng)域的程序包(統(tǒng)稱 util.concurrent),該程序包包含許多可以簡化高性能并行編程的實用程序類。 這些類中包含兩個 Map,即 ConcurrentReaderHashMap 和 ConcurrentHashMap。 這些 Map 實現(xiàn)是線程安全的,并且不需要對并發(fā)訪問或更新進行同步,同時還適用于大多數(shù)需要 Map 的情況。 它們還遠比同步的 Map(如 Hashtable)或使用同步的包裝器更具伸縮性,并且與 HashMap 相比,它們對性能的破壞很小。 util.concurrent 程序包構(gòu)成了 JSR166 的基礎(chǔ);JSR166 已經(jīng)開發(fā)了一個包含在 Java 1.5 版中的并發(fā)實用程序,而 Java 1.5 版將把這些 Map 包含在一個新的 java.util.concurrent 程序包中。

          所有這一切意味著您不需要一個決策樹來決定是使用同步的 Map 還是使用非同步的 Map, 而只需使用 ConcurrentHashMap。 當(dāng)然,在某些情況下,使用 ConcurrentHashMap 并不合適。 但這些情況很少見,并且應(yīng)具體情況具體處理。 這就是監(jiān)測的用途。


          結(jié)束語

          通過 Oracle JDeveloper 可以非常輕松地創(chuàng)建一個用于比較各種 Map 性能的測試類。 更重要的是,集成良好的監(jiān)測器可以在開發(fā)過程中快速、輕松地識別性能瓶頸 - 集成到 IDE 中的監(jiān)測器通常被較頻繁地使用,以便幫助構(gòu)建一個成功的工程。 現(xiàn)在,您已經(jīng)擁有了一個監(jiān)測器并了解了有關(guān)通用 Map 及其性能的基礎(chǔ)知識,可以開始運行您自己的測試,以查明您的應(yīng)用程序是否因 Map 而存在瓶頸以及在何處需要更改所使用的 Map。

          以上內(nèi)容介紹了通用 Map 及其性能的基礎(chǔ)知識。 當(dāng)然,有關(guān)特定 Map 實現(xiàn)以及如何根據(jù)不同的需求使用它們還存在更多復(fù)雜和值得關(guān)注的事項,這些將在本文第 2 部分中介紹。


          --------------------------------------------------------------------------------
          Jack Shirazi 是 O''Reilly 的“Java 性能調(diào)整”的作者,以及受歡迎的 JavaPerformanceTuning.com 網(wǎng)站(提供 Java 性能信息的全球知名站點)的總監(jiān)。 Jack 在 Java 性能領(lǐng)域提供咨詢并著書立說。 他還監(jiān)督 JavaPerformanceTuning.com 提供的信息,其中包括每年大約發(fā)布 1000 條性能技巧以及許多有關(guān)性能工具、討論組等內(nèi)容的文章。 Jack 早年還曾發(fā)布有關(guān)蛋白質(zhì)結(jié)構(gòu)預(yù)測以及黑洞熱力學(xué)方面的文章,而且在其空閑時還對某些 Perl5 核心模塊作出了貢獻。

          posted @ 2005-12-06 13:16 只牽這只狗 閱讀(627) | 評論 (0)編輯 收藏

          原著:Steve Mansour
          sman@scruznet.com
          Revised: June 5, 1999
          (copied by jm /at/ jmason.org from http://www.scruz.net/%7esman/regexp.htm, after the original disappeared! )

          翻譯:Neo Lee
          什么是正則表達式

          一個正則表達式,就是用某種模式去匹配一類字符串的一個公式。很多人因為它們看上去比較古怪而且復(fù)雜所以不敢去使用——很不幸,這篇文章也不能夠改變這一點,不過,經(jīng)過一點點練習(xí)之后我就開始覺得這些復(fù)雜的表達式其實寫起來還是相當(dāng)簡單的,而且,一旦你弄懂它們,你就能把數(shù)小時辛苦而且易錯的文本處理工作壓縮在幾分鐘(甚至幾秒鐘)內(nèi)完成。正則表達式被各種文本編輯軟件、類庫(例如Rogue Wave的tools.h++)、腳本工具(像awk/grep/sed)廣泛的支持,而且像Microsoft的Visual C++這種交互式IDE也開始支持它了。

          我們將在如下的章節(jié)中利用一些例子來解釋正則表達式的用法,絕大部分的例子是基于vi中的文本替換命令和grep文件搜索命令來書寫的,不過它們都是比較典型的例子,其中的概念可以在sed、awk、perl和其他支持正則表達式的編程語言中使用。你可以看看不同工具中的正則表達式這一節(jié),其中有一些在別的工具中使用正則表達式的例子。還有一個關(guān)于vi中文本替換命令(s)的簡單說明附在文后供參考。

          正則表達式基礎(chǔ)

          正則表達式由一些普通字符和一些元字符(metacharacters)組成。普通字符包括大小寫的字母和數(shù)字,而元字符則具有特殊的含義,我們下面會給予解釋。

          在最簡單的情況下,一個正則表達式看上去就是一個普通的查找串。例如,正則表達式"testing"中沒有包含任何元字符,,它可以匹配"testing"和"123testing"等字符串,但是不能匹配"Testing"。

          要想真正的用好正則表達式,正確的理解元字符是最重要的事情。下表列出了所有的元字符和對它們的一個簡短的描述。

          元字符   描述


          .
          匹配任何單個字符。例如正則表達式r.t匹配這些字符串:ratrutr t,但是不匹配root。 
          $
          匹配行結(jié)束符。例如正則表達式weasel$ 能夠匹配字符串"He's a weasel"的末尾,但是不能匹配字符串"They are a bunch of weasels."。 
          ^
          匹配一行的開始。例如正則表達式^When in能夠匹配字符串"When in the course of human events"的開始,但是不能匹配"What and When in the"。
          *
          匹配0或多個正好在它之前的那個字符。例如正則表達式.*意味著能夠匹配任意數(shù)量的任何字符。
          \
          這是引用府,用來將這里列出的這些元字符當(dāng)作普通的字符來進行匹配。例如正則表達式\$被用來匹配美元符號,而不是行尾,類似的,正則表達式\.用來匹配點字符,而不是任何字符的通配符。
          [ ] 
          [c1-c2]
          [^c1-c2]
          匹配括號中的任何一個字符。例如正則表達式r[aou]t匹配ratrotrut,但是不匹配ret。可以在括號中使用連字符-來指定字符的區(qū)間,例如正則表達式[0-9]可以匹配任何數(shù)字字符;還可以制定多個區(qū)間,例如正則表達式[A-Za-z]可以匹配任何大小寫字母。另一個重要的用法是“排除”,要想匹配除了指定區(qū)間之外的字符——也就是所謂的補集——在左邊的括號和第一個字符之間使用^字符,例如正則表達式[^269A-Z] 將匹配除了2、6、9和所有大寫字母之外的任何字符。
          \< \>
          匹配詞(word)的開始(\<)和結(jié)束(\>)。例如正則表達式\<the能夠匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:這個元字符不是所有的軟件都支持的。
          \( \)
          將 \( 和 \) 之間的表達式定義為“組”(group),并且將匹配這個表達式的字符保存到一個臨時區(qū)域(一個正則表達式中最多可以保存9個),它們可以用 \1\9 的符號來引用。
          |
          將兩個匹配條件進行邏輯“或”(Or)運算。例如正則表達式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:這個元字符不是所有的軟件都支持的。
          +
          匹配1或多個正好在它之前的那個字符。例如正則表達式9+匹配9、99、999等。注意:這個元字符不是所有的軟件都支持的。
          ?
          匹配0或1個正好在它之前的那個字符。注意:這個元字符不是所有的軟件都支持的。
          \{i\}
          \{i,j\}
          匹配指定數(shù)目的字符,這些字符是在它之前的表達式定義的。例如正則表達式A[0-9]\{3\} 能夠匹配字符"A"后面跟著正好3個數(shù)字字符的串,例如A123、A348等,但是不匹配A1234。而正則表達式[0-9]\{4,6\} 匹配連續(xù)的任意4個、5個或者6個數(shù)字字符。注意:這個元字符不是所有的軟件都支持的。


          最簡單的元字符是點,它能夠匹配任何單個字符(注意包括新行符)。假定有個文件test.txt包含以下幾行內(nèi)容:

            he is a rat
            he is in a rut
            the food is Rotten
            I like root beer

          我們可以使用grep命令來測試我們的正則表達式,grep命令使用正則表達式去嘗試匹配指定文件的每一行,并將至少有一處匹配表達式的所有行顯示出來。命令

            grep r.t test.txt

          在test.txt文件中的每一行中搜索正則表達式r.t,并打印輸出匹配的行。正則表達式r.t匹配一個r接著任何一個字符再接著一個t。所以它將匹配文件中的ratrut,而不能匹配Rotten中的Rot,因為正則表達式是大小寫敏感的。要想同時匹配大寫和小寫字母,應(yīng)該使用字符區(qū)間元字符(方括號)。正則表達式[Rr]能夠同時匹配Rr。所以,要想匹配一個大寫或者小寫的r接著任何一個字符再接著一個t就要使用這個表達式:[Rr].t

          要想匹配行首的字符要使用抑揚字符(^)——又是也被叫做插入符。例如,想找到text.txt中行首"he"打頭的行,你可能會先用簡單表達式he,但是這會匹配第三行的the,所以要使用正則表達式^he,它只匹配在行首出現(xiàn)的h

          有時候指定“除了×××都匹配”會比較容易達到目的,當(dāng)抑揚字符(^)出現(xiàn)在方括號中是,它表示“排除”,例如要匹配he ,但是排除前面是t or s的情性(也就是theshe),可以使用:[^st]he

          可以使用方括號來指定多個字符區(qū)間。例如正則表達式[A-Za-z]匹配任何字母,包括大寫和小寫的;正則表達式[A-Za-z][A-Za-z]* 匹配一個字母后面接著0或者多個字母(大寫或者小寫)。當(dāng)然我們也可以用元字符+做到同樣的事情,也就是:[A-Za-z]+ ,和[A-Za-z][A-Za-z]*完全等價。但是要注意元字符+ 并不是所有支持正則表達式的程序都支持的。關(guān)于這一點可以參考后面的正則表達式語法支持情況

          要指定特定數(shù)量的匹配,要使用大括號(注意必須使用反斜杠來轉(zhuǎn)義)。想匹配所有1001000的實例而排除1010000,可以使用:10\{2,3\},這個正則表達式匹配數(shù)字1后面跟著2或者3個0的模式。在這個元字符的使用中一個有用的變化是忽略第二個數(shù)字,例如正則表達式0\{3,\} 將匹配至少3個連續(xù)的0。

          簡單的例子

          這里有一些有代表性的、比較簡單的例子。

          vi 命令 作用


          :%s/ */ /g 把一個或者多個空格替換為一個空格。
          :%s/ *$// 去掉行尾的所有空格。
          :%s/^/ / 在每一行頭上加入一個空格。
          :%s/^[0-9][0-9]* // 去掉行首的所有數(shù)字字符。
          :%s/b[aeio]g/bug/g 將所有的bagbegbigbog改為bug。 
          :%s/t\([aou]\)g/h\1t/g 將所有tagtogtug分別改為hathothug(注意用group的用法和使用\1引用前面被匹配的字符)。

          中級的例子(神奇的咒語)

          例1

          將所有方法foo(a,b,c)的實例改為foo(b,a,c)。這里a、b和c可以是任何提供給方法foo()的參數(shù)。也就是說我們要實現(xiàn)這樣的轉(zhuǎn)換:

          之前   之后
          foo(10,7,2) foo(7,10,2)
          foo(x+13,y-2,10) foo(y-2,x+13,10)
          foo( bar(8), x+y+z, 5) foo( x+y+z, bar(8), 5)

          下面這條替換命令能夠?qū)崿F(xiàn)這一魔法:

            :%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo(\2,\1,\3)/g

          現(xiàn)在讓我們把它打散來加以分析。寫出這個表達式的基本思路是找出foo()和它的括號中的三個參數(shù)的位置。第一個參數(shù)是用這個表達式來識別的::\([^,]*\),我們可以從里向外來分析它: 

          [^,]   除了逗號之外的任何字符
          [^,]* 0或者多個非逗號字符
          \([^,]*\) 將這些非逗號字符標記為\1,這樣可以在之后的替換模式表達式中引用它
          \([^,]*\), 我們必須找到0或者多個非逗號字符后面跟著一個逗號,并且非逗號字符那部分要標記出來以備后用。

          現(xiàn)在正是指出一個使用正則表達式常見錯誤的最佳時機。為什么我們要使用[^,]*這樣的一個表達式,而不是更加簡單直接的寫法,例如:.*,來匹配第一個參數(shù)呢?設(shè)想我們使用模式.*來匹配字符串"10,7,2",它應(yīng)該匹配"10,"還是"10,7,"?為了解決這個兩義性(ambiguity),正則表達式規(guī)定一律按照最長的串來,在上面的例子中就是"10,7,",顯然這樣就找出了兩個參數(shù)而不是我們期望的一個。所以,我們要使用[^,]*來強制取出第一個逗號之前的部分。

          這個表達式我們已經(jīng)分析到了:foo(\([^,]*\),這一段可以簡單的翻譯為“當(dāng)你找到foo(就把其后直到第一個逗號之前的部分標記為\1”。然后我們使用同樣的辦法標記第二個參數(shù)為\2。對第三個參數(shù)的標記方法也是一樣,只是我們要搜索所有的字符直到右括號。我們并沒有必要去搜索第三個參數(shù),因為我們不需要調(diào)整它的位置,但是這樣的模式能夠保證我們只去替換那些有三個參數(shù)的foo()方法調(diào)用,在foo()是一個重載(overoading)方法時這種明確的模式往往是比較保險的。然后,在替換部分,我們找到foo()的對應(yīng)實例,然后利用標記好的部分進行替換,是的第一和第二個參數(shù)交換位置。

          例2

          假設(shè)有一個CSV(comma separated value)文件,里面有一些我們需要的信息,但是格式卻有問題,目前數(shù)據(jù)的列順序是:姓名,公司名,州名縮寫,郵政編碼,現(xiàn)在我們希望講這些數(shù)據(jù)重新組織,以便在我們的某個軟件中使用,需要的格式為:姓名,州名縮寫-郵政編碼,公司名。也就是說,我們要調(diào)整列順序,還要合并兩個列來構(gòu)成一個新列。另外,我們的軟件不能接受逗號前后面有任何空格(包括空格和制表符)所以我們還必須要去掉逗號前后的所有空格。

          這里有幾行我們現(xiàn)在的數(shù)據(jù):

            Bill Jones,     HI-TEK Corporation ,  CA, 95011
            Sharon Lee Smith,  Design Works Incorporated,  CA, 95012
            B. Amos   ,  Hill Street Cafe,  CA, 95013
            Alexander Weatherworth,  The Crafts Store,  CA, 95014
            ...

          我們希望把它變成這個樣子:

            Bill Jones,CA 95011,HI-TEK Corporation
            Sharon Lee Smith,CA 95012,Design Works Incorporated
            B. Amos,CA 95013,Hill Street Cafe
            Alexander Weatherworth,CA 95014,The Crafts Store
            ...

          我們將用兩個正則表達式來解決這個問題。第一個移動列和合并列,第二個用來去掉空格。

          下面就是第一個替換命令:

            :%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/\1,\3 \4,\2/

          這里的方法跟例1基本一樣,第一個列(姓名)用這個表達式來匹配:\([^,]*\),即第一個逗號之前的所有字符,而姓名內(nèi)容被用\1標記下來。公司名和州名縮寫字段用同樣的方法標記為\2\3,而最后一個字段用\(.*\)來匹配("匹配所有字符直到行末")。替換部分則引用上面標記的那些內(nèi)容來進行構(gòu)造。

          下面這個替換命令則用來去除空格:

            :%s/[ \t]*,[ \t]*/,/g

          我們還是分解來看:[ \t]匹配空格/制表符,[ \t]* 匹配0或多個空格/制表符,[ \t]*,匹配0或多個空格/制表符后面再加一個逗號,最后,[ \t]*,[ \t]*匹配0或多個空格/制表符接著一個逗號再接著0或多個空格/制表符。在替換部分,我們簡單的我們找到的所有東西替換成一個逗號。這里我們使用了結(jié)尾的可選的g參數(shù),這表示在每行中對所有匹配的串執(zhí)行替換(而不是缺省的只替換第一個匹配串)。

          例3

          假設(shè)有一個多字符的片斷重復(fù)出現(xiàn),例如:

          Billy tried really hard
          Sally tried really really hard
          Timmy tried really really really hard
          Johnny tried really really really really hard

          而你想把"really"、"really really",以及任意數(shù)量連續(xù)出現(xiàn)的"really"字符串換成一個簡單的"very"(simple is good!),那么以下命令:

          :%s/\(really \)\(really \)*/very /

          就會把上述的文本變成:

          Billy tried very hard
          Sally tried very hard
          Timmy tried very hard
          Johnny tried very hard

          表達式\(really \)*匹配0或多個連續(xù)的"really "(注意結(jié)尾有個空格),而\(really \)\(really \)* 匹配1個或多個連續(xù)的"really "實例。

          困難的例子(不可思議的象形文字)

          Coming soon.


          不同工具中的正則表達式

          OK,你已經(jīng)準備使用RE(regular expressions,正則表達式),但是你并準備使用vi。所以,在這里我們給出一些在其他工具中使用RE的例子。另外,我還會總結(jié)一下你在不同程序之間使用RE可能發(fā)現(xiàn)的區(qū)別。

          當(dāng)然,你也可以在Visual C++編輯器中使用RE。選擇Edit->Replace,然后選擇"Regular expression"選擇框,F(xiàn)ind What輸入框?qū)?yīng)上面介紹的vi命令:%s/pat1/pat2/g中的pat1部分,而Replace輸入框?qū)?yīng)pat2部分。但是,為了得到vi的執(zhí)行范圍和g選項,你要使用Replace All或者適當(dāng)?shù)氖止ind Next and Replace(譯者按:知道為啥有人罵微軟弱智了吧,雖然VC中可以選中一個范圍的文本,然后在其中執(zhí)行替換,但是總之不夠vi那么靈活和典雅)。

          sed

          Sed是Stream EDitor的縮寫,是Unix下常用的基于文件和管道的編輯工具,可以在手冊中得到關(guān)于sed的詳細信息。

          這里是一些有趣的sed腳本,假定我們正在處理一個叫做price.txt的文件。注意這些編輯并不會改變源文件,sed只是處理源文件的每一行并把結(jié)果顯示在標準輸出中(當(dāng)然很容易使用重定向來定制):

          sed腳本   描述


          sed 's/^$/d' price.txt 刪除所有空行
          sed 's/^[ \t]*$/d' price.txt 刪除所有只包含空格或者制表符的行
          sed 's/"http://g' price.txt 刪除所有引號

          awk

          awk是一種編程語言,可以用來對文本數(shù)據(jù)進行復(fù)雜的分析和處理。可以在手冊中得到關(guān)于awk的詳細信息。這個古怪的名字是它作者們的姓的縮寫(Aho,Weinberger和Kernighan)。

          在Aho,Weinberger和Kernighan的書The AWK Programming Language中有很多很好的awk的例子,請不要讓下面這些微不足道的腳本例子限制你對awk強大能力的理解。我們同樣假定我們針對price.txt文件進行處理,跟sed一樣,awk也只是把結(jié)果顯示在終端上。 

          awk腳本   描述


          awk '$0 !~ /^$/' price.txt 刪除所有空行
          awk 'NF > 0' price.txt awk中一個更好的刪除所有行的辦法
          awk '$2 ~ /^[JT]/ {print $3}' price.txt 打印所有第二個字段是'J'或者'T'打頭的行中的第三個字段
          awk '$2 !~ /[Mm]isc/ {print $3 + $4}' price.txt 針對所有第二個字段不包含'Misc'或者'misc'的行,打印第3和第4列的和(假定為數(shù)字)
          awk '$3 !~ /^[0-9]+\.[0-9]*$/ {print $0}' price.txt 打印所有第三個字段不是數(shù)字的行,這里數(shù)字是指d.d或者d這樣的形式,其中d是0到9的任何數(shù)字
          awk '$2 ~ /John|Fred/ {print $0}' price.txt 如果第二個字段包含'John'或者'Fred'則打印整行

          grep

          grep是一個用來在一個或者多個文件或者輸入流中使用RE進行查找的程序。它的name編程語言可以用來針對文件和管道進行處理。可以在手冊中得到關(guān)于grep的完整信息。這個同樣古怪的名字來源于vi的一個命令,g/re/p,意思是global regular expression print。

          下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個逗號,然后是名,然后是一個制表符,然后是電話號碼:

            Francis, John           5-3871
            Wong, Fred              4-4123
            Jones, Thomas           1-4122
            Salazar, Richard        5-2522

          grep命令   描述


          grep '\t5-...1' phone.txt 把所有電話號碼以5開頭以1結(jié)束的行打印出來,注意制表符是用\t表示的
          grep '^S[^ ]* R' phone.txt 打印所有姓以S打頭和名以R打頭的行
          grep '^[JW]' phone.txt 打印所有姓開頭是J或者W的行
          grep ', ....\t' phone.txt 打印所有姓是4個字符的行,注意制表符是用\t表示的
          grep -v '^[JW]' phone.txt 打印所有不以J或者W開頭的行
          grep '^[M-Z]' phone.txt 打印所有姓的開頭是M到Z之間任一字符的行
          grep '^[M-Z].*[12]' phone.txt 打印所有姓的開頭是M到Z之間任一字符,并且點號號碼結(jié)尾是1或者2的行

          egrep

          egrep是grep的一個擴展版本,它在它的正則表達式中支持更多的元字符。下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個逗號,然后是名,然后是一個制表符,然后是電話號碼:

            Francis, John           5-3871
            Wong, Fred              4-4123
            Jones, Thomas           1-4122
            Salazar, Richard        5-2522

          egrep command   Description


          egrep '(John|Fred)' phone.txt 打印所有包含名字John或者Fred的行
          egrep 'John|22$|^W' phone.txt 打印所有包含John 或者以22結(jié)束或者以W的行
          egrep 'net(work)?s' report.txt 從report.txt中找到所有包含networks或者nets的行


          正則表達式語法支持情況

          命令或環(huán)境 . [ ] ^ $ \( \) \{ \} ? + | ( )
          vi  X   X   X   X   X           
          Visual C++  X   X   X   X   X           
          awk  X   X   X   X       X   X   X   X 
          sed  X   X   X   X   X   X         
          Tcl  X   X   X   X   X     X   X   X   X 
          ex  X   X   X   X   X   X         
          grep  X   X   X   X   X   X         
          egrep  X   X  X   X   X     X   X   X   X 
          fgrep  X   X   X   X   X           
          perl  X  X  X  X  X    X  X  X  X

           


          vi替換命令簡介

          Vi的替換命令:

            :ranges/pat1/pat2/g

          其中

            : 這是Vi的命令執(zhí)行界面。
            range 是命令執(zhí)行范圍的指定,可以使用百分號(%)表示所有行,使用點(.)表示當(dāng)前行,使用美元符號($)表示最后一行。你還可以使用行號,例如10,20表示第10到20行,.,$表示當(dāng)前行到最后一行,.+2,$-5表示當(dāng)前行后兩行直到全文的倒數(shù)第五行,等等。

            s 表示其后是一個替換命令。

            pat1 這是要查找的一個正則表達式,這篇文章中有一大堆例子。

            pat2 這是希望把匹配串變成的模式的正則表達式,這篇文章中有一大堆例子。

            g 可選標志,帶這個標志表示替換將針對行中每個匹配的串進行,否則則只替換行中第一個匹配串。

          網(wǎng)上有很多vi的在線手冊,你可以訪問他們以獲得更加完整的信息。



          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=539524

          posted @ 2005-12-06 09:25 只牽這只狗 閱讀(205) | 評論 (0)編輯 收藏

               摘要: Posted on 2005-11-24 00:21 BlueO2 閱讀(469) 評論(0)  編輯 收藏 收藏至365Key 所屬分類: AJAX --> 本想翻譯IBM的一篇文章 Build apps using Asynchronous JavaScript with XML 但是發(fā)現(xiàn)不如就按照那個方式想怎么寫就怎么寫。之后有時間了會把其中的一個系列...  閱讀全文
          posted @ 2005-12-05 17:12 只牽這只狗 閱讀(362) | 評論 (0)編輯 收藏

          瀏覽器端框架被劃分成兩大類:

          ·應(yīng)用程序框架:提供瀏覽器的功能,但是常以包括窗口小部件抽象和另外的部件而出名,其功能主要圍繞桌面GUI框架。

          ·基本結(jié)構(gòu)框架:提供基本的管道和可移植的瀏覽器抽象,讓開發(fā)者去創(chuàng)建內(nèi)容。典型的功能:

          * 針對XMLHttpRequest的包裝器以封裝瀏覽器-服務(wù)器的交互。(所有的框架都提供這一功能)。

          * XML操作和查詢。

          * 根據(jù)來自XMLHttpRequest的應(yīng)答執(zhí)行DOM操作。

          * 在一些情況中,與另外的瀏覽器端技術(shù)如Flash(和潛在的Java applets)集成在一起。

          而服務(wù)器端框架通常以下面兩種方式工作(盡管它們在這里根據(jù)語言的不同進行了分類):

          ·HTML/JS生成:服務(wù)器提供完整的HTML/Javascript代碼生成和瀏覽器-服務(wù)器協(xié)調(diào),結(jié)果是只有瀏覽器端編碼可以被定制。

          ·遠程調(diào)用:Javascript調(diào)用直接被路由到服務(wù)器端功能(例如Java方法)并返回到Javascript回叫處理器;或者Javascript調(diào)用服務(wù)器以提取信息,例如會話細節(jié),數(shù)據(jù)庫查詢等。

          ·純Javascript:應(yīng)用程序框架

          1.1 Bindows(自從2003年)

          網(wǎng)址是:http://www.bindows.net,Bindows是一個軟件開發(fā)包(SDK),它,通過強力聯(lián)合DHTML,JavaScript,CSS和XML等技術(shù),能生成高度交互的互聯(lián)網(wǎng)應(yīng)用程序-成為現(xiàn)代的桌面應(yīng)用程序的強有力對手。Bindows應(yīng)用程序不要求下載和也不需要在用戶端安裝-僅要求有一個瀏覽器(也不需要Java,F(xiàn)lash或者ActiveX)。Bindows有可能領(lǐng)導(dǎo)面向?qū)ο箝_發(fā)的AJAX應(yīng)用程序的平臺。

          ·它是商業(yè)化的,使用來自于MB的技術(shù)(總部位于GA USA,主要開發(fā)中心在瑞典,成立于2002年)。

          Bindows框架提供給你:

          ·基于類的面向?qū)ο蟮腁PI

          ·一套完整的窗口系統(tǒng),提供寬范圍的窗口小部件支持,包括菜單、表單、格子、滑動條、量程,甚至更多

          ·用于開發(fā)zero-footprint SOA客戶端應(yīng)用程序的領(lǐng)先的工具箱

          ·本機的XML,SOAP和XML-RPC支持

          ·單用戶到企業(yè)級的支持

          ·內(nèi)建的對AJAX的支持

          Bindows開發(fā)環(huán)境:

          ·支持企業(yè)級規(guī)模的工程開發(fā)

          ·跨瀏覽器,跨平臺支持

          ·服務(wù)器獨立結(jié)構(gòu)

          ·與新的和現(xiàn)有資源的互操作性

          ·一致性開發(fā)方法學(xué)

          1.2 BackBase(自從2003年)

          網(wǎng)址是:http://www.backbase.com,是一個全面的瀏覽器端框架,支持豐富的瀏覽器功能以及與.NET和Java的集成。

          ·商業(yè)化,來自于Backbase B.V(總部在Amsterdam,成立于2003年)。

          1.3 DOJO(開發(fā)中;自從2004年9月)

          網(wǎng)址是:http://dojotoolkit.org/,提供全面窗口小組件和瀏覽器-服務(wù)器消息支持。

          ·為創(chuàng)建定制的Javascript窗口小組件提供框架支持。

          ·預(yù)置的窗口小組件庫。

          ·瀏覽器-服務(wù)器消息支持-XMLHttpRequest和另外的機制。

          ·支持瀏覽器中的URL操縱功能。

          ·開源許可(學(xué)術(shù)自由許可2.1(http://opensource.org/licenses/afl-2.1.php)),由JotSpot(http://www.jot.com/)的Alex Russell(http://alex.dojotoolkit.org/)所領(lǐng)導(dǎo)。

          1.4 Open Rico(開發(fā)中;自從2005年5月;基于早期的私有框架)

          網(wǎng)址是:http://openrico.org/demos.page,是一多用途框架,支持Ajax基礎(chǔ)結(jié)構(gòu)和用戶交互。

          ·一個XMLHttpRequest應(yīng)答能被路由到一個或者更多回叫操作,DOM對象,或者Javascript對象。

          ·容易鼠標拖動支持。

          ·Ajax動畫,例如縮放和變換。

          ·"行為"-實質(zhì)上是窗口小組件庫。

          ·使用指南(http://www.mirimar.net/mailbrowser/),由RussMirimar的Yonah所提供

          ·開源。源于Sabre航空公司解決方案,由Bill Scott(http://looksgoodworkswell.blogspot.com),Darren James及另外一些人所支持。

          1.5 qooxdoo(開發(fā)中;自從2005年5月)

          網(wǎng)址是:http://qooxdoo.sourceforge.net/,是另一個雄心勃勃的框架,提供寬范圍的UI支持和正在開發(fā)中的基礎(chǔ)結(jié)構(gòu)特性。

          ·基礎(chǔ)結(jié)構(gòu):

          * DOM和事件/焦點管理的可移植的抽象。

          * 調(diào)試支持。

          * 易于時間調(diào)度的Timer類。

          * Getter/Setter支持。

          ·UI:

          * 窗口小組件框架和預(yù)置的窗口小組件庫。

          * 布局管理器。

          * 圖像緩沖和可移植的PNG透明性。

          ·開源(LGPL)。來自多方面的貢獻者。

          1.6 Tibet(開發(fā)中;自從2005年6月)

          網(wǎng)址是:http://www.technicalpursuit.com/,目的是提供高度可移植的和全面的Javascript API,結(jié)果是,可能自動生成大量的客戶端代碼。自稱是"企業(yè)級Ajax"。

          ·遠程腳本運行在XMLHttpRequest包裝之上-通過協(xié)調(diào)調(diào)用結(jié)果支持工作流管理,例如應(yīng)答可以發(fā)生在只有當(dāng)兩個分離的調(diào)用返回時。

          ·URI支持。

          ·所有的HTTP方法-不僅是"GET"和"POST"。

          ·低級的協(xié)議-File://和WebDav以及HTTP。

          ·Web服務(wù)調(diào)用-SOAP,XML-RPC,等等。

          ·預(yù)置的針對Google API,Amazon API等等服務(wù)的支持。

          ·由高級Javascript對象組成一個巨大的庫。

          ·許多XML操作。

          ·IDE和開發(fā)工具。

          ·開源許可(顯然經(jīng)過OSI認證,但是細節(jié)不多)。

          2 純Javascript:基礎(chǔ)結(jié)構(gòu)框架

          2.1 AjaxCaller(Alpha版本;自從5月2005年)

          網(wǎng)址是:http://ajaxify.com/run/testAjaxCaller/,是一基本的線程安全的XMLHttpRequest包裝器,主要針對Ajax新手,仍處于原始的alpha開發(fā)階段,目前僅與AjaxPatterns的在線搜索范例一起打包。

          ·實現(xiàn)對服務(wù)器的調(diào)用(GET/POST/PUT/DELETE),用路由到一個回叫操作的plain-text或者XML完成。

          ·使用過的XMLHttpRequest對象的析構(gòu)。

          ·Response緩沖(計劃的)。

          ·針對Ajax新手-并非強調(diào)性能優(yōu)化,該庫主要用于實現(xiàn)易讀的基礎(chǔ)代碼并將提供調(diào)試支持。

          ·開源許可。由Michael Mahemoff(http://softwareas.com)(具有John Wehr和Richard Schwartz的一些思想)維護。

          2.2 Flash JavaScript集成包

          網(wǎng)址是:http://www.osflash.org/doku.php?id=flashjs,允許JavaScript和Flash內(nèi)容的集成:

          ·使JavaScript能夠調(diào)用ActionScript功能和反過來的實現(xiàn)。

          ·所有主要的數(shù)據(jù)類型能在這兩種環(huán)境之間傳遞。

          ·開源許可。由多個開源Flash貢獻者提供支持。

          2.3 Google AJAXSLT(發(fā)行于2005年6月)

          網(wǎng)址是:http://goog-ajaxslt.sourceforge.net/,是一個Javascript框架,用來執(zhí)行XSLT轉(zhuǎn)換以及XPath查詢。

          ·建立在Google地圖工作基礎(chǔ)之上。

          ·開源許可(BSD)。由一家創(chuàng)新搜索方案公司支持,自稱為"Google"。

          2.4 HTMLHttpRequest(Beta版;始于2005年)

          HtmlHttpRequest(http://www.twinhelix.com/javascript/htmlhttprequest/),它使用了XMLHttpRequest和Iframes以改進兼容性。

          ·測試過并能工作在:IE6/Win,IE5.5/Win,IE5/Win,IE4/Win,Mozilla/Win,Opera7/Win,Safari/Mac,IE5/Mac。

          ·未測試,可能能工作在:IE4/Mac,Mozilla/Mac,Opera/Other,Konqueror/Linux。你正在使用這些之一嗎?作者正在請求兼容性信息。

          ·開源許可(LGPL)。由Twin Helix Designs(http://www.twinhelix.com/)的Angus Turnbull維護。

          2.5 交互式網(wǎng)站框架(自從2005年5月)

          交互式網(wǎng)站框架(http://sourceforge.net/projects/iwf/,是一個項目,目的是從瀏覽器端對Ajax基礎(chǔ)結(jié)構(gòu)的多方面予以支持。自描述為"使用javascript,css,xml,和html來創(chuàng)造高度交互網(wǎng)站的框架。包括一個定制的針對高度可讀的javascript的xml分析器。實質(zhì)上,是建立基于AJAX的網(wǎng)站的基礎(chǔ),還有另外一些通用腳本"。

          ·線程安全的XMLHttpRequest實現(xiàn)。

          ·針對XML文檔的包裝器,以便你能夠創(chuàng)建更具可讀性的代碼:

          var node = doc.groceries.frozen[0].pizza[0].size;</pre>

          代替手工的導(dǎo)航:

          var node = doc.documentElement.firstChild.firstChild.getAttribute("size");</pre>

          ·開源許可。由Weaver(http://circaware.com|Brock)維護。

          2.6 LibXMLHttpRequest(發(fā)行于2003年6月)

          libXmlRequest(http://www.whitefrost.com/servlet/connector?file=reference/2003/06/17/libXmlRequest.html),是XMLHttpRequest的一個瘦包裝器。

          ·getXML()和postXML()方法。

          ·XMLHttpRequest對象池支持。

          ·Response緩沖。

          ·可用源碼(明顯),但是受標準版權(quán)的保護,由Stephen W.Coate(http://www.whitefrost.com/index.jsp)所維護。

          2.7 RSLite(x)

          網(wǎng)站是:http://www.ashleyit.com/rs/main.htm,是一個針對XMLHttpRequest的瘦包裝器。

          ·一個簡單的組件,作為Brent Ashley的更全面的遠程腳本工作(參見Javascript遠程腳本-JSRS在多語言服務(wù)器端)的一部分發(fā)行。

          2.8 Sack(在開發(fā)中,自從2005年5月)

          網(wǎng)站是:http://twilightuniverse.com/2005/05/sack-of-ajax/,是一個針對XMLHttpRequest的瘦包裝器。

          ·調(diào)用者能指定回叫函數(shù)或者回叫DOM對象。借助于回叫DOM,應(yīng)答文本直接被推入到DOM中

          2.9 Sarissa(發(fā)行于2月,2003年)

          網(wǎng)站是:http://sarissa.sf.net,是一種Javascript API,它封裝了在瀏覽器端可以獨立調(diào)用XML的功能。

          ·可移植的XMLHttpRequest創(chuàng)建

          ·可移植的XPath查詢

          ·可移植的DOM操作

          ·可移植的XSLT

          ·可移植的XML串行化

          ·開源(GPL2.0和LGPL2.1)。來自多方面貢獻者。

          2.10 XHConn(發(fā)行于自從4月,2005年)

          網(wǎng)站是:http://xkr.us/code/javascript/XHConn/,是一個對XMLHttpRequest的瘦包裝器。

          ·例如:

          new XHConn().connect("mypage.php","POST","foo=bar&baz=qux",fnWhenDone);

          ·開源許可。由Brad Fults所維護。

          服務(wù)器端:多種語言

          3.1 跨平臺異步的接口工具箱(5月2005年)

          CPAINT:http://cpaint.sourceforge.net/,是一真正的支持PHP和ASP/Vbscript的Ajax實現(xiàn)和JSRS(JavaScript遠程腳本)實現(xiàn)。CPAINT提供給你需求的代碼在后臺實現(xiàn)AJAX和JSRS,而返回的數(shù)據(jù)以JavaScript形式在前臺操作,格式化和顯示。這允許你創(chuàng)建能提供接近實時的反饋給用戶的web應(yīng)用程序。

          ·支持PHP&ASP

          ·針對所有函數(shù)的一致的JavaScript文件

          ·支持遠程腳本和XML

          ·支持本地和遠程函數(shù)

          ·單個或者多個XMLHTTP對象

          ·以文本或者JavaScript XML/DOM文檔對象方式返回后臺數(shù)據(jù)

          ·能支持POST和GET請求

          ·后臺代理函數(shù)來訪問遠程函數(shù)和數(shù)據(jù)

          ·在所有的主要瀏覽器上測試過

          ·在GNU GPL&LGPL保護下發(fā)行

          3.2 SAJAX(可用,但是不是1.0版本;自從3月2005年)

          網(wǎng)站是:http://www.modernmethod.com/sajax/,直接把調(diào)用從Javascript發(fā)送到你的服務(wù)器端語言并再次回返。例如,調(diào)用一個javascript方法x_calculateBudget(),將先到達服務(wù)器和調(diào)用一個Java calculateBudget()方法,然后以javascript方式把值返回到x_calculateBudget_cb()。

          ·便利從Javascript代理函數(shù)到后臺操作的映射。

          ·能夠代理對眾多服務(wù)器端平臺(ASP/ColdFusion/Io/Lua/Perl/PHP/Python/Ruby)的調(diào)用。

          ·開源許可。來自多方面貢獻者。

          3.3 Javascipt對象標志(JSON)和JSON-RPC

          JSON(http://www.crockford.com/JSON/index.html),是一個"胖的自由的XML選擇",而JSON-RPC(http://www.json-rpc.org/)是一種遠程過程協(xié)議,類似于XML-RPC,強有力支持Javascript客戶。

          ·實現(xiàn)多服務(wù)器端平臺(http://www.json-rpc.org/impl.xhtml):Java,Python,Ruby,Perl。

          ·針對每種平臺有獨立的打包和許可,如JSON-RPC-Java(http://oss.metaparadigm.com/jsonrpc/)。

          3.4 Javascript遠程腳本(JSRS)(自從2000年)

          網(wǎng)址是:http://www.ashleyit.com/rs/jsrs/test.htm,直接把調(diào)用從Javascript發(fā)送到你的服務(wù)器端語言并再次回返。

          ·知名的瀏覽器:IE4+,NS4.x,NS6.x,Mozilla,Opera7和Galeon。

          ·服務(wù)器端支持:ASP,ColdFusion,PerlCGI,PHP,Python和JSP(servlet)。

          ·開源許可。由Brent Ashley(http://www.ashleyit.com/)提供支持。

          4 服務(wù)器端:Java

          注意:許多現(xiàn)有的框架最近正在添加Java支持(例如struts),我將在后面指出。

          4.1 WebORB for Java(自從2005年8月)

          網(wǎng)址:http://www.themidnightcoders.com/weborb/aboutWeborb.htm,是一個平臺,支持開發(fā)AJAX和基于Flash的胖客戶端應(yīng)用程序,并可以把它們與Java對象和XML Web服務(wù)相系起來。在線舉例(http://www.themidnightcoders.com/examples)

          ·WebORB包括一個稱作豐富的客戶系統(tǒng)(http://www.themidnightcoders.com/rcs/index.htm)的客戶端庫。該豐富的客戶系統(tǒng)提供一簡單的在線api來綁定到并調(diào)用任何Java對象,XML Web服務(wù)或者EJB上的方法。

          ·支持同步的和異步的方法調(diào)用。

          ·并不要求在服務(wù)器端代碼上作任何修改,不需要定制方法屬性,特別的簽名或者參數(shù)類型。★不要求設(shè)計時生成代理。

          ·同步調(diào)用返回來自于該調(diào)用(不需要回叫)的數(shù)據(jù)。異步的調(diào)用依賴于一個回叫實現(xiàn)。

          ·任何服務(wù)器端方法能被同步地或者異步地調(diào)用。

          ·客戶應(yīng)用程序能向服務(wù)器對象請求指定的活動方式。結(jié)果,對象能被輕易地創(chuàng)建而不需任何特殊的編程

          ·提供一個特定API來處理數(shù)據(jù)庫查詢結(jié)果-服務(wù)器代碼能返回Data集合或者Data表,而客戶端以一個特殊RecordSet JavaScript對象來顯示這個結(jié)果。該對象提供一個方法以檢索列名和行數(shù)據(jù)。

          ·支持數(shù)據(jù)分頁技術(shù)。客戶應(yīng)用程序能檢索頁面中的數(shù)據(jù)。

          ·支持所有的服務(wù)器端參數(shù)類型并返回值-原型,字符串,復(fù)合類型,數(shù)組,本機.net集合,遠程參考。

          ·共有兩種版本可用:標準版(自由)和專業(yè)版(商業(yè)許可)

          4.2 Echo 2(自從3月2005年)

          網(wǎng)址是:http://www.nextapp.com/products/echo2/,允許你用純Java代碼編寫Ajax應(yīng)用軟件(范例(http://demo.nextapp.com/InteractiveTest/ia))。

          自動地生成HTML和Javascript。

          ·協(xié)調(diào)瀏覽器和服務(wù)器之間的消息。消息形式為XML。

          ·如果需要,可以手工編寫定制的Javascript部件。

          ·開源許可(Mozilla公共許可或者GNU LGPL)。源于Next App,Inc.(http://www.nextapp.com/)。

          4.3 Direct Web Remoting (DWR)(2005年)

          網(wǎng)址是:http://www.getahead.ltd.uk/dwr/,是一個框架,用于直接從Javascript代碼中調(diào)用Java方法。

          ·象SAJAX,能把Javascript中的調(diào)用傳遞到Java方法,并返回到Javascript回叫。

          ·能與任何web框架(Struts,Tapestry,等等)一起使用。

          ·開源許可(Apache(http://www.apache.org/LICENSE.txt))。由Joe Walker(http://www.getahead.ltd.uk/sg/space/joe/)所支持。被加入到WebWork(http://www.opensymphony.com/webwork/)版本。

          4.4 SWATO(2005年)

          網(wǎng)址是:http://swato.dev.java.net/,是一套可重用的和良好集成的Java/JavaScript庫,它實現(xiàn)了一種更容易的方式來改變你的web應(yīng)用程序的交互,它是通過AJAX方式實現(xiàn)。

          ·服務(wù)器端Java庫能被容易地配置到所有的Servlet 2.3+匹配的容器中。

          ·客戶端JavaScript庫能工作在支持HttpXMLRequest的各種瀏覽器中。

          ·使用JSON來在服務(wù)器端編組你的POJO數(shù)據(jù)。這樣你能存取在任何JavaScript環(huán)境(HTML,XUL,SVG)中的遠程數(shù)據(jù),這種存取可以容易地通過硬編碼或者與某種成熟的JavaScript庫集成來實現(xiàn)。

          ·提供一個簡單的接口來使你的JavaScript代碼可以與暴露在客戶端的遠程POJO交互(RPC等)。

          ·使用web.xml中的<servlet>和<filter>的容易且靈活的配置,并能(但不是依賴)與Spring集成到一起。

          ·提供了幾個可幫助你快速開發(fā)web應(yīng)用程序的組件(如自動完成的文本框,在線表單,在線列表,等等)。

          5 服務(wù)器端:Lisp

          5.1 CL-Ajax

          網(wǎng)址:http://cliki.net/cl-ajax,實現(xiàn)Javascript直接調(diào)用服務(wù)器端Lisp函數(shù)。

          ·如下輸出函數(shù):

          (export-函數(shù) #’my-函數(shù))

          ·可以產(chǎn)生帶有參數(shù)的Javascript代理。

          ·能回叫Javascript函數(shù)或者DOM對象。

          ·可以被集成進SAJAX。

          ·開源(定制,非常靈活,許可)。由[Richard Newman](http://www.holygoat.co.uk/)所維護。

          6 服務(wù)器端:.NET

          6.1 WebORB for.NET(自從8月2005年)

          網(wǎng)址:http://www.themidnightcoders.com/weborb/aboutWeborb.htm,是一個平臺,用于開發(fā)AJAX和基于Flash的胖客戶端應(yīng)用程序,并能把它們連接到.NET對象和XML Web服務(wù)。(在線舉例(http://www.themidnightcoders.com/examples))

          ·WebORB包括一個客戶端庫,名叫Rich Client System(http://www.themidnightcoders.com/rcs/index.htm)。Rich Client System提供一簡單的在線api以綁定到和調(diào)用任何.NET對象或者XML Web服務(wù)上的任何方法。

          ·支持同步和異步的方法調(diào)用

          ·并不要求在服務(wù)器端代碼上作任何修改,不需要定制方法屬性,特別的簽名或者參數(shù)類型。**不要求設(shè)計時代理生成。

          ·同步調(diào)用返回來自于該調(diào)用的數(shù)據(jù)(不需要回叫)。異步的調(diào)用依賴于一個回叫實現(xiàn)。

          ·任何服務(wù)器端方法能被同步地或者異步地調(diào)用。

          ·客戶應(yīng)用程序能向服務(wù)器對象請求指定的活動方式。結(jié)果,對象能被輕易地創(chuàng)建而不需任何特殊的編程

          ·提供一個特定API來處理數(shù)據(jù)庫查詢結(jié)果-服務(wù)器代碼能返回DataSet或者DataTable,而客戶端以一個特殊RecordSet JavaScript對象來顯示這個結(jié)果。該對象提供一個方法以檢索列名和行數(shù)據(jù)

          ·支持數(shù)據(jù)頁面技術(shù)。客戶端應(yīng)用程序能檢索頁面中的數(shù)據(jù)。

          ·支持所有的服務(wù)器端參數(shù)類型并返回值-原型,字符串,復(fù)合類型,數(shù)組,本機.net集合,遠程參考

          ·共有兩種版本可用的:標準版(自由)和專業(yè)版(商業(yè)許可)

          6.2 Ajax.NET(自從3月2005年)

          網(wǎng)址是:http://ajax.schwarz-interactive.de/,是一個庫,實現(xiàn)從Javascript到服務(wù)器端.NET的存取。

          ·象SAJAX,能把Javascript中的調(diào)用傳遞到.NET方法,并返回到Javascript回叫。

          ·能存取來自于JavaScript的會話數(shù)據(jù)。

          ·緩存結(jié)果

          ·自由使用,可用的源碼,未指定使用許可。由Michael Schwarz(http://weblogs.asp.net/mschwarz/)所維護。

          ·不允許改變源代碼,用屬性標記方法

          ·完整的類支持以返回客戶端JavaScript值

          ·使用HtmlControls來進行輸入和返回值

          ·可以返回數(shù)據(jù)表,數(shù)據(jù)集,數(shù)據(jù)視圖,數(shù)組和集合

          7 服務(wù)器端:PHP

          7.1 AjaxAC(自從2005年4月)

          網(wǎng)址是:http://ajax.zervaas.com.au/,用單個的PHP類封裝了完整的應(yīng)用程序。

          ·所有的應(yīng)用程序代碼是自包含在單個類中(附加另外一些JavaScript庫)

          ·干凈利索地調(diào)用PHP文件/HTML頁面。只需創(chuàng)建應(yīng)用程序類,然后參照應(yīng)用程序JavaScript和依附任何需要的HTML元素到該應(yīng)用程序。

          ·容易地處理JavaScript事件的內(nèi)嵌功能

          ·創(chuàng)建子需要并處理它們的內(nèi)嵌功能

          ·允許定制的配置值,因此某些單元能在運行時間設(shè)置

          ·無凌亂的JavaScript代碼夾雜在調(diào)用HTML的代碼中-所有的事件是被動態(tài)依附的

          ·由于以上兩個原因容易和模板引擎集成到一起

          ·容易鉤到(hook in to)已有的PHP類或者MySQL數(shù)據(jù)庫以返回來自于子需求的數(shù)據(jù)

          ·能夠容易地進一步生成JavaScript對象的可擴展的窗口小組件結(jié)構(gòu)(但是還需要做一些工作)

          背景:

          ·開源許可(Apache2.0)。由Zervaas Enterprises(http://ajax.zervaas.com.au/)支持

          7.2 JPSpan

          網(wǎng)址是:http://jpspan.sourceforge.net/wiki/doku.php,直接把Javascript調(diào)用傳遞到PHP函數(shù)。

          ·進行了嚴肅的單元測試。

          ·開源許可(PHP)。

          7.3 XAJAX

          網(wǎng)址是:http://xajax.sf.net,直接把Javascript調(diào)用傳遞到PHP函數(shù)。

          ·使用Javascript代理來調(diào)用PHP腳本。

          ·開源。由J.Max Wilson所創(chuàng)。

          8 服務(wù)器端:Ruby

          Ruby On Rails(http://www.rubyonrails.org/)是一個通常的強力支持Ajax的web框架:

          ·當(dāng)Ajax出現(xiàn)的時候Rails還處于其發(fā)展的早期,因此Ajax可能逐漸成為Rails框架的核心。

          ·生成瀏覽器中大多數(shù)/全部的窗口小組件和動畫的Javascript腳本。

          ·支持服務(wù)器端調(diào)用。

          ·調(diào)度支持。

          ·開源許可。



          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=542157

          posted @ 2005-12-05 13:19 只牽這只狗 閱讀(235) | 評論 (0)編輯 收藏

          僅列出標題
          共3頁: 上一頁 1 2 3 下一頁 
          主站蜘蛛池模板: 富蕴县| 信宜市| 顺义区| 鹿泉市| 竹山县| 宕昌县| 灵武市| 开平市| 公主岭市| 宜黄县| 祁东县| 永登县| 翼城县| 镇江市| 桂阳县| 布拖县| 望江县| 宜章县| 安远县| 耒阳市| 汪清县| 吉木乃县| 河津市| 廊坊市| 大兴区| 白沙| 蒙山县| 韶山市| 延庆县| 伊宁市| 高台县| 安化县| 莎车县| 丹巴县| 城市| 新余市| 隆昌县| 邢台县| 新邵县| 长葛市| 宜川县|