隨筆 - 14, 文章 - 0, 評論 - 15, 引用 - 0
          數(shù)據(jù)加載中……

          java&XML學(xué)習(xí)第三天,cocoon2

                由于對于cocoon 2的內(nèi)容特別的感興趣,所以跳過了對sax的學(xué)習(xí)就直接開始了cocoon 2的學(xué)習(xí),事實(shí)證明這樣是不對的,如果你只是想對cocoon 2作一個(gè)簡單的了解,可以不學(xué)sax,但是如果想要深入了解cocoon 2的話,還是應(yīng)該先學(xué)習(xí)sax。
                首先,關(guān)于cocoon入門的資料網(wǎng)上比較少,一個(gè)是ibm上提供的三個(gè)cocoon的教程,比較不錯(cuò),另外就是cocoon自己的文檔,還有就是必須研究cocoon的源代碼了。

                一、cocoon是什么?
                按照我的理解,cocoon是一個(gè)整套的java web開發(fā)框架,象struts里面可以實(shí)現(xiàn)的功能,在cocoon里面其實(shí)都可以實(shí)現(xiàn),但是,我覺得他的側(cè)重點(diǎn)應(yīng)該是用于在web以各種樣式上發(fā)布xml內(nèi)容(Html,pdf,SVG),他提供了內(nèi)容、邏輯、表現(xiàn)在很大程度上的分離,這一點(diǎn)不是struts這種MVC框架的強(qiáng)項(xiàng)。
                至于說有人將cocoon和struts進(jìn)行比較,我覺得應(yīng)該是不恰當(dāng)?shù)?,因?yàn)閮烧咧亟鉀Q的問題是不同的,如果你是一個(gè)新聞網(wǎng)站,以發(fā)布內(nèi)容為主,那么你可以考慮cocoon,但是如果你是一個(gè)信息管理系統(tǒng),側(cè)重于事物的處理,那么你可以選擇struts以及webwork2等框架。

                二、cocoon能干什么?
          • 提供靜態(tài)文件和動(dòng)態(tài)生成的響應(yīng)
          • 使用任意數(shù)量的處理將用戶請求透明地映射到物理資源
          • 執(zhí)行簡單和多級(jí) XSLT 轉(zhuǎn)換
          • 將參數(shù)動(dòng)態(tài)傳遞到 XSLT 變換
          • 生成各種各樣的輸出格式,包括 XML、HTML、PNG、JPEG、SVG 和 PDF

                以上是ibm教程上的原話,可能只有最后的一條比較容易理解,不過希望您在讀完本文以后可以對上述的特性都有一個(gè)大概的理解。

                三、為什么是cocoon 2?
                cocoon1和cocoon2是cocoon的兩個(gè)不同的版本,其主要的區(qū)別是cocoon1是圍繞dom接口開發(fā)的,這是一種效率較低的api,而cocoon2是圍繞sax的。所以在學(xué)習(xí)cocoon2之前,建議了解sax和xml的相關(guān)知識(shí)。

                四、開始進(jìn)入cocoon 2的世界,管道模型
                安裝配置就不說了,網(wǎng)上可以找到相應(yīng)的說明,而且熟悉java web的人應(yīng)該可以知道如何安裝。
                下面就說一說cocoon 2里面最重要的一個(gè)概念:管道
                一個(gè)管道是由一個(gè)輸入開始,一個(gè)輸出結(jié)束,其中您可以加入任意多的對輸入數(shù)據(jù)的處理模塊。所以,在cocoon 2中,一個(gè)管道應(yīng)該是1輸入+n處理+1輸出。所有這些模塊,在cocoon中被稱為“components”。
                下面是cocoon 2中內(nèi)置的幾個(gè)較為常用的模塊:
                管道輸入 — 生成器(如FileGenerator,HTMLGenerator,DirectoryGenerator)和閱讀器(常用來讀靜態(tài)文件)
            處理步驟 — 轉(zhuǎn)換器(如XSLT 轉(zhuǎn)換器)和操作
            管道輸出 — 序列化器(如XML,HTML,SVG,PDF序列化器 )
            條件的處理 — 匹配器和選擇器 
                cocoon的管道通常至少有生成器和序列化器,也就是我們說的輸入和輸出。這里面有個(gè)感念前面在學(xué)習(xí)xsl的時(shí)候提到過,就是對xml的轉(zhuǎn)換和格式化輸出是分開的,在cocoon里面很好的體現(xiàn)了這一點(diǎn)。

                五、站點(diǎn)地圖
                實(shí)際上,一個(gè)最簡單的管道應(yīng)該是使用匹配器來接受用戶請求(URL請求),使用生成器生成xml,使用各種轉(zhuǎn)換器,使用序列化器輸出。所有這些,將體現(xiàn)在cocoon的一個(gè)配置文件里面sitemap.xmap,就構(gòu)成了所謂的“站點(diǎn)地圖”。
                下面是我做測試使用的站點(diǎn)地圖:

          <?xml version="1.0" encoding="UTF-8"?>
          <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

            
          <map:components>(1)
              
          <!-- component declarations -->
              
          <map:generators default="file">
                    
          <map:generator name="file" src="org.apache.cocoon.generation.FileGenerator"/>
                    
          <map:generator  name="xsp" src="org.apache.cocoon.generation.ServerPagesGenerator"/>
                    
          <map:generator name="helloWorld" src="simpletest.SimpleTest"/>
                  
          </map:generators>
                  
                  
          <map:transformers default="xslt">
                    
          <map:transformer  name="xslt" src="org.apache.cocoon.transformation.TraxTransformer"/>
                  
          </map:transformers>
                  
                  
          <map:readers default="resource">
                    
          <map:reader name="resource" src="org.apache.cocoon.reading.ResourceReader"/>
                  
          </map:readers>
                  
                  
          <map:serializers default="html">
                    
          <map:serializer name="xml" mime-type="text/xml" src="org.apache.cocoon.serialization.XMLSerializer"/>
                    
          <map:serializer name="html" mime-type="text/html" src="org.apache.cocoon.serialization.HTMLSerializer"/>
                    
          <map:serializer name="svg2png" src="org.apache.cocoon.serialization.SVGSerializer" mime-type="image/png"/>
                    
          <map:serializer name="fo2pdf" src="org.apache.cocoon.serialization.FOPSerializer" mime-type="application/pdf"/>
                  
          </map:serializers>
                  
                  
          <map:matchers default="wildcard">
                    
          <map:matcher name="wildcard" src="org.apache.cocoon.matching.WildcardURIMatcher"/>
                  
          </map:matchers>

              
          <map:actions/>
              
          <map:selectors/>
            
          </map:components>

           
          <map:pipelines>
           
            
          <map:pipeline>
             
          <map:match pattern="*.xml">(4)
                
          <map:generate type="xsp" src="{1}.xsp"/>
                
          <map:serialize type="xml"/>
             
          </map:match>
             
          <map:match pattern="welcome">(2)
              
          <map:generate src="samples.xml"/>
              
          <map:transform src="simple-samples2html.xsl"/>
              
          <map:serialize type="html"/>
             
          </map:match>
             
          <map:match pattern="heyThere">(3)
                
          <map:generate type="helloWorld"/>
                
          <map:serialize type="xml"/>
             
          </map:match>
             
            
          </map:pipeline>
            
           
          </map:pipelines>

          </map:sitemap>

                為了節(jié)省篇幅,我把后面的東西也放進(jìn)來,以后會(huì)慢慢解釋這個(gè)文件,先看圖中的(1),是所有的組件的定義。
                (2)就是一個(gè)簡單的管道。從他的內(nèi)容可以看出,首先,他匹配welcome的用戶請求,假使是:http://localhost:8089/cocoon-dev/welcome,然后,有一個(gè)生成器,使用的是默認(rèn)的FileGenerator生成器,這個(gè)生成器將會(huì)讀取samples.xml文件,把它作為這個(gè)管道的輸入。
                之后,有一個(gè)xsl的轉(zhuǎn)換器,他使用simple-samples2html.xsl來轉(zhuǎn)化生成器生成的xml,最后由一個(gè)html的序列化器生成輸出。simples.xml和simple-samples2html.xsl的代碼就不給出了,熟悉xml&xslt的朋友應(yīng)該明白。
                在瀏覽器中輸入http://localhost:8089/cocoon-dev/welcome后就會(huì)得到輸出的html頁面。當(dāng)然,如果你將轉(zhuǎn)換器和序列化器的定義修改成:
                  <map:transform src="transforms/content2rss.xsl"/>
                    <map:serialize type="xml"/>
                   或者
                   <map:transform src="transforms/content2fo.xsl"/>
                   <map:serialize type="fo2pdf"/>
          的話,你將會(huì)得到rss和pdf格式的輸出。個(gè)人認(rèn)為這應(yīng)該是cocoon的最主要的功能,這也是我了解cocoon的主要原因。

                六、使用cocoon進(jìn)行開發(fā)
                在cocoon 2的tutorial里面有這樣的一個(gè)章節(jié)介紹使用cocoon進(jìn)行web的開發(fā),但是其中只講到了自定義生成器的部分,個(gè)人認(rèn)為cocoon 2的建議是把查詢數(shù)據(jù)庫,邏輯運(yùn)算,商業(yè)邏輯等功能都放在生成器里面、xsp就是一種生成器他的寫法類似于jsp,但是不管是自定義的生成器還是xsp,其接口都比較復(fù)雜,我覺得并沒有struts來的方便,當(dāng)然這又回到了開始的話題,應(yīng)用的地方不同,沒有好壞之分,這里只是為了研究一下cocoon2的內(nèi)部結(jié)構(gòu)。
              下面是一個(gè)自定義的生成器:

          package simpletest;

          import org.apache.cocoon.generation.AbstractGenerator;
          import org.xml.sax.helpers.AttributesImpl;
          import org.xml.sax.SAXException;

          public class SimpleTest extends AbstractGenerator 
          {

              AttributesImpl emptyAttr 
          = new AttributesImpl();

              
          /**
               * Override the generate() method from AbstractGenerator.
               * It simply generates SAX events using SAX methods.  
               * I haven't done the comparison myself, but this 
               * has to be faster than parsing them from a string.
               
          */


              
          public void generate() throws SAXException
              
              
          {
                 
                
          // the org.xml.sax.ContentHandler is inherited 
                
          // through org.apache.cocoon.xml.AbstractXMLProducer 

                contentHandler.startDocument();
                
                contentHandler.startElement(
          """example""example", emptyAttr);
                
                contentHandler.characters(
          "Hello World!".toCharArray(),0,
                                            
          "Hello World!".length());

                contentHandler.endElement(
          "","example""example");

                contentHandler.endDocument();

              }

          }
                可以看到生成器的接口并不那么簡單,這里只寫一個(gè)generate方法是因?yàn)槔^承了很多的類,他們給你提供了好多方法。
                第二點(diǎn)就是我們的generate方法里面寫的是sax事件的調(diào)用,也就是說,在執(zhí)行g(shù)enerate方法的時(shí)候,contentHandler就好像在讀取一個(gè)xml文件一樣。為了證明這一點(diǎn),我們有了管道中(3)的配置。運(yùn)行http://localhost:8089/cocoon-dev/heyThere之后,我們有了如下結(jié)果:
            <?xml version="1.0" encoding="UTF-8" ?> 
            
          <example>Hello World!</example> 
                我們可以理解以上的xml文件就是generate的輸出,原因是序列化器是個(gè)xml序列化器,他其實(shí)并沒有對generate的輸出作什么操作。
                更進(jìn)一步的說,我們可以這樣理解,generate輸出一個(gè)xml,管道的下一個(gè)處理器接受到這個(gè)xml以后進(jìn)行一些操作,生成另外一個(gè)xml,以此類推,直到序列化器的出現(xiàn),把xml轉(zhuǎn)化成了想要的格式。這其實(shí)就是cocoon的基本工作原理。

                七、實(shí)際原理
                上面說的工作原理可以通過依次取掉generate后面的處理器,而在最后加裝xml的序列化器來驗(yàn)證,但是在cocoon的內(nèi)部,卻沒有什么xml被傳來傳去,那么管道的各個(gè)組件之間是怎樣協(xié)作的呢?在教程上有句話說是通過互相傳遞sax事件實(shí)現(xiàn)的,乍一聽來非常難以理解,經(jīng)過了無數(shù)次調(diào)試后,終于得知了實(shí)情。
                我們來看如下的代碼:
          private void connectPipeline(Environment   environment,
                                           ArrayList     usedTransformers,
                                           XMLSerializer xmlSerializer)
              throws ProcessingException 
          {
                  XMLProducer prev 
          = this.producer;
                  XMLConsumer next;

                  boolean configuredSAXConnector 
          = this.manager.hasComponent(SAXConnector.ROLE);

                  
          try {
                      
          int cacheableTransformerCount = this.firstNotCacheableTransformerIndex;

                      Iterator itt 
          = usedTransformers.iterator();
                      
          while ( itt.hasNext() ) {
          .......................
                          next = (XMLConsumer) itt.next();
          .......................
              
                          prev.setConsumer(next);
                          prev 
          = (XMLProducer) next;
                      }


          ........................
                      }

                      prev.setConsumer(next);

                  }
           catch .............

              }
                上面是cocoon代碼中的一些片斷,從中我們可以看出,cocoon把一個(gè)管道里面的所有的組件進(jìn)行一次循環(huán),把前一個(gè)組件的XMLConsumer設(shè)成后一個(gè)組件,也就是后面的組件是前面組件的XML消費(fèi)者,而對于后一個(gè)組件來說,前一個(gè)是XMLProducer ,也就是XML生產(chǎn)者。
                而且,通過調(diào)試得知,每一個(gè)組件,不管是什么類型,都會(huì)有一個(gè)XMLConsumer的屬性,另外,還都會(huì)有一個(gè)contentHandler的屬性。ContentHandler這個(gè)類是標(biāo)準(zhǔn)的sax接口,從這一點(diǎn)分析,XMLConsumer有可能是cocoon1的殘留物,而真正在cocoon2里面其作用的是ContentHandler這個(gè)接口的一些實(shí)現(xiàn)類。
                后面又進(jìn)行了一些調(diào)試,結(jié)果卻是驗(yàn)證了上面的說法,為了測試做了如下的配置:
                <map:match pattern="welcome">
                  <map:generate type="helloWorld"/>
                  <map:transform src="simple-samples2html.xsl"/>
                  <map:transform src="simple-samples2html2.xsl"/>
                  <map:serialize type="xml"/>
                </map:match>
          結(jié)果是這樣的,自定義的generate類的generate()方法中的contentHandler.startDocument();一句的實(shí)現(xiàn)代碼如下:這段代碼在AbstractXMLPipe這個(gè)類中
          public void startDocument()
              throws SAXException 
          {
                  
          if (contentHandler != null) contentHandler.startDocument();
              }
          也就是說,generate的屬性contentHandler中還有個(gè)contentHandler屬性,依次遞歸調(diào)用,后續(xù)的測試得出如下的結(jié)論:
          generate的對象我們稱之為g1,
          generate的contentHandler屬性就是TraxTransformer類的一個(gè)對象,也就是
          <map:transform src="simple-samples2html.xsl"/>這一句的實(shí)現(xiàn)載體,我們暫且稱這之對象為t1,
          而<map:transform src="simple-samples2html2.xsl"/>的實(shí)現(xiàn)載體對象我們暫稱之為t2,
          <map:serialize type="xml"/>的實(shí)現(xiàn)載體是XMLSerializer類的一個(gè)對象,我們暫稱之為s1
          他們之間的關(guān)系是g1.contentHandler = t1.contentHandler = t2.contentHandler = s1.contentHandler,而且所有的contentHandler都是AbstractXMLPipe這個(gè)類的某一個(gè)子類型,也就是說他們的startDocument()等方法的實(shí)現(xiàn)都是完全一樣的。
          這樣一來,每一個(gè)sax的事件將會(huì)在generate.generate()方法中被開始調(diào)用,并不斷地遞歸g1,t1,t2.....s1,這就是cocoon管道之間各個(gè)組件互相傳遞數(shù)據(jù)的真相。

                八、其他一些技術(shù)的了解:
                cocoon中比較有用的一些技術(shù)還有xsp和esql,其中xsp是一個(gè)類似jsp的組件,他在cocoon中的地位應(yīng)該是一種generate,用來生成最初的xml,并且,他可以內(nèi)嵌java代碼,就像jsp那樣,取得request參數(shù),查詢數(shù)據(jù)庫等,如站點(diǎn)地圖中的(4)所示,我們可以把這樣的一個(gè)組件作為管道的起點(diǎn),這樣我們查詢或者業(yè)務(wù)處理的結(jié)果就可以通過管道被發(fā)布成各種樣式了!
                下面給出一個(gè)xsp的簡單例子:
          <xsp:page language="java"
                            xmlns:xsp
          ="http://apache.org/xsp">
             
          <xsp:structure>
                
          <xsp:include>java.util.Calendar</xsp:include>
                
          <xsp:include>java.text.*</xsp:include>
             
          </xsp:structure>

             
          <document>

                
          <xsp:logic>
                   SimpleDateFormat format = new SimpleDateFormat("EEE, MMM d, yyyy");
                   String timestamp = format.format(
                                             java.util.Calendar.getInstance().getTime()
                                             );
                
          </xsp:logic>

                
          <time><xsp:expr>timestamp</xsp:expr></time>
                
          <time><xsp:expr>request</xsp:expr></time>

                
          <!-- additional elements -->
             
          </document>
          </xsp:page>
          其中:<xsp:logic>標(biāo)簽和<xsp:expr>標(biāo)簽就類似于jsp中的<%%>和<%=%>
                esql是在xsp上使用的一項(xiàng)技術(shù),他應(yīng)該類似于jsp的一些標(biāo)簽庫,實(shí)現(xiàn)的功能是操作數(shù)據(jù)庫,直接寫在xsp文件中的,這樣可以很方便的生成一個(gè)由數(shù)據(jù)庫驅(qū)動(dòng)的動(dòng)態(tài)的xml,配合上cocoon的其他組件,也就是說可以很方便的把數(shù)據(jù)庫中的東西發(fā)布成各種版本。
                下面是他的一些語法定義:
          <xsp:page
            
          language="java"
            xmlns:xsp
          ="http://apache.org/xsp"
            xmlns:esql
          ="http://apache.org/cocoon/SQL/v2">

          <root>
            
          <esql:connection>

             
          <esql:execute-query>

               
          <!-- connection
               information 
          -->
               
          <esql:pool/>

               
          <!-- SQL query -->
               
          <esql:query/>

               
          <!-- result processing
               elements 
          -->
               
          <esql:results/>
               
          <esql:update-results/>
               
          <esql:no-results/>
               
          <esql:error-results/>

              
          </esql:execute-query>

             
          </esql:connection>

          </root>

          </xsp:page>

                九、struts&cocoon
                目前,已經(jīng)有人想到了struts和cocoon的整合,用struts來處理邏輯層的事物,用cocoon來實(shí)現(xiàn)多種表現(xiàn)形式,操作方法大概提供一個(gè)struts的plugin,可以把struts最終的jsp作為cocoon的xml源來使用。
                地址:http://struts.sourceforge.net/struts-cocoon/
                不過個(gè)人認(rèn)為這種結(jié)合的方式還是比較生硬,記得以前看到過關(guān)于strutsX的有關(guān)介紹,希望這種事物處理層和表現(xiàn)層同樣強(qiáng)大的框架可以早點(diǎn)出來,順便說一句,cocoon 2項(xiàng)目以前是屬于apache xml項(xiàng)目下的,現(xiàn)在已經(jīng)是一個(gè)獨(dú)立的項(xiàng)目http://cocoon.apache.org,在這里也祝愿cocoon能夠飛的更高,飛得更遠(yuǎn)。

                第一次寫那么多,試試發(fā)布一下,純粹是可望志同道合的人交流,各位高手見笑了^_^

          posted on 2005-03-10 15:38 Boris-Java 閱讀(2178) 評論(2)  編輯  收藏 所屬分類: java&xml

          評論

          # re: java&XML學(xué)習(xí)第三天,cocoon2  回復(fù)  更多評論   

          很好哦!謝謝!
          2006-05-09 09:57 | popoer

          # re: java&XML學(xué)習(xí)第三天,cocoon2  回復(fù)  更多評論   

          寫的很有深度,對作者表示敬佩
          2006-11-09 16:44 | guest
          主站蜘蛛池模板: 台中市| 游戏| 阜南县| 丹巴县| 乌兰察布市| 云南省| 秦皇岛市| 汶川县| 曲麻莱县| 定边县| 贺兰县| 甘谷县| SHOW| 阿合奇县| 华蓥市| 自贡市| 奉贤区| 卓资县| 三台县| 平山县| 丹巴县| 阳曲县| 聊城市| 城固县| 武义县| 华宁县| 探索| 柳江县| 中宁县| 乌拉特前旗| 祁阳县| 渭源县| 河间市| 曲阳县| 禄劝| 新竹县| 江口县| 屯昌县| 明溪县| 伽师县| 衡南县|