隨筆-179  評論-666  文章-29  trackbacks-0
          本文從實(shí)踐的角度重點(diǎn)闡述Java語言中輸入流類StreamTokenizer在編寫HTML文件分析程序中的應(yīng)用,并介紹了以字節(jié)為單位下載Web頁面的例程。
            
            一、概述
            
            Web服務(wù)器的核心是對HTML文件中的各標(biāo)記(Tag)作出正確的分析,一種編程語言的解釋程序也是對源文件中的保留字進(jìn)行分析再做解釋的。實(shí)際應(yīng)用中,我們也常常會遇到需要對某一特定類型文件進(jìn)行關(guān)鍵字分析的情況,比如,需要將某個(gè)HTML文件下載并同時(shí)下載與之相關(guān)的.gif、.class等文件,此時(shí)就要求對HTML文件中的標(biāo)記進(jìn)行分離,找出所需的文件名及目錄。在Java出現(xiàn)以前,類似工作需要對文件中的每個(gè)字符進(jìn)行分析,從中找出所需部分,不僅編程量大,且易出錯(cuò)。筆者在近期的項(xiàng)目中利用Java的輸入流類StreamTokenizer進(jìn)行HTML文件的分析,效果較好。在此,我們要實(shí)現(xiàn)從已知的Web頁面下載HTML文件,對其進(jìn)行分析后,下載該頁面中包含的HTML文件(如果在Frame中)、圖像文件和Class(Java Applet)文件。
            
            二、StreamTokenizer類
            
            StreamTokenizer即令牌化輸入流的作用是將一個(gè)輸入流中變成令牌流。令牌流中的令牌實(shí)體有三類:單詞(即多字符令牌)、單字符令牌和空白(包括Java和C/C++中的說明語句)。
            
            StreamTokenizer類的構(gòu)造器為: StreamTokenizer(InputStream in)
            
            該類有一些公有實(shí)例變量:ttype、sval和nval ,分別表示令牌類型、當(dāng)前字符串值和當(dāng)前數(shù)字值。當(dāng)我們需要取得令牌(即HTML中的標(biāo)記)之間的字符時(shí),應(yīng)訪問變量sval。而讀向下一個(gè)令牌的方法是調(diào)用nextToken()。方法nextToken()的返回值是int型,共有四種可能的返回:
            
            StreamTokenizer.TT_NUMBER: 表示讀到的令牌是數(shù)字,數(shù)字的值是double型,可以從實(shí)例變量nval中讀取。
            
            StreamTokenizer.TT_WORD: 表示讀到的令牌是非數(shù)字的單詞(其他字符也在其中),單詞可以從實(shí)例變量sval中讀取。
            
            StreamTokenizer.TT_EOL: 表示讀到的令牌是行結(jié)束符。
            
            如果已讀到流的盡頭,則nextToken()返回TT_EOF。
            
            開始調(diào)用nextToken()之前,要設(shè)置輸入流的語法表,以便使分析器辨識不同的字符。WhitespaceChars(int low, int hi)方法定義沒有意義的字符的范圍。WordChars(int low, int hi)方法定義構(gòu)造單詞的字符范圍。
            
            三、程序?qū)崿F(xiàn)
            
            1、HtmlTokenizer類的實(shí)現(xiàn)
            
            對某個(gè)令牌流進(jìn)行分析之前,首先應(yīng)對該令牌流的語法表進(jìn)行設(shè)置,在本例中,即是讓程序分出哪個(gè)單詞是HTML的標(biāo)記。下面給出針對我們需要的HTML標(biāo)記的令牌流類定義,它是StreamTokenizer的子類:

          ?1???????? import?java.io.*;?
          ?2  import?java.lang.String;?
          ?3  class?HtmlTokenizer?extends?
          ?4  StreamTokenizer?{?
          ?5  //定義各標(biāo)記,這里的標(biāo)記僅是本例中必須的,?
          ?6  可根據(jù)需要自行擴(kuò)充?
          ?7  ?static?int?HTML_TEXT=-1;?
          ?8  ?static?int?HTML_UNKNOWN=-2;?
          ?9  ?static?int?HTML_EOF=-3;?
          10  ?static?int?HTML_IMAGE=-4;?
          11  ?static?int?HTML_FRAME=-5;?
          12  ?static?int?HTML_BACKGROUND=-6;?
          13  ?static?int?HTML_APPLET=-7;?
          14  ?
          15  boolean?outsideTag=true;?//判斷是否在標(biāo)記之中?
          16  ?
          17  ?//構(gòu)造器,定義該令牌流的語法表。?
          18  ?public?HtmlTokenizer(BufferedReader?r)?{?
          19  super(r);?
          20  this.resetSyntax();?//重置語法表?
          21  this.wordChars(0,255);?//令牌范圍為全部字符?
          22  this.ordinaryChar('<?');?//HTML標(biāo)記兩邊的分割符?
          23  this.ordinaryChar('>');?
          24  ?}
          ?//end?of?constructor?
          25  ?
          26  ?public?int?nextHtml(){?
          27  int?token;?//令牌?
          28  try{?
          29  switch(token=this.nextToken()){?
          30  case?StreamTokenizer.TT_EOF:?
          31  //如果已讀到流的盡頭,則返回TT_EOF?
          32  return?HTML_EOF;?
          33  case?'<?':?//進(jìn)入標(biāo)記字段?
          34  outsideTag=false;?
          35  return?nextHtml();?
          36  case?'>':?//出標(biāo)記字段?
          37  outsideTag=true;?
          38  return?nextHtml();?
          39  case?StreamTokenizer.TT_WORD:?
          40  //若當(dāng)前令牌為單詞,判斷是哪個(gè)標(biāo)記?
          41  if?(allWhite(sval))?
          42  ?return?nextHtml();?//過濾其中空格?
          43  else?if(sval.toUpperCase().indexOf("FRAME")?
          44  !=-1?&&?!outsideTag)?//標(biāo)記FRAME?
          45  ?return?HTML_FRAME;?
          46  else?if(sval.toUpperCase().indexOf("IMG")?
          47  !=-1?&&?!outsideTag)?//標(biāo)記IMG?
          48  ?return?HTML_IMAGE;?
          49  else?if(sval.toUpperCase().indexOf("BACKGROUND")?
          50  !=-1?&&?!outsideTag)?//標(biāo)記BACKGROUND?
          51  ?return?HTML_BACKGROUND;?
          52  else?if(sval.toUpperCase().indexOf("APPLET")?
          53  !=-1?&&?!outsideTag)?//標(biāo)記APPLET?
          54  ?return?HTML_APPLET;?
          55  default:?
          56  System.out.println?("Unknown?tag:?"+token);?
          57  return?HTML_UNKNOWN;?
          58  ?}
          ?//end?of?case?
          59  }
          catch(IOException?e){?
          60  System.out.println("Error:"+e.getMessage());}
          ?
          61  return?HTML_UNKNOWN;?
          62  ?}
          ?//end?of?nextHtml?
          63  ?
          64  protected?boolean?allWhite(String?s){//過濾所有空格?
          65  //實(shí)現(xiàn)略?
          66  ?}
          //?end?of?allWhite?
          67  ?
          68  }
          ?//end?of?class?
          69


          posted on 2007-01-18 16:58 Alpha 閱讀(1633) 評論(3)  編輯  收藏 所屬分類: Java J2EE JSP

          評論:
          # re: [轉(zhuǎn)]利用Java編寫HTML文件分析程序 2007-09-04 16:04 | yslin_1985
          非常感謝你的轉(zhuǎn)載,我正要用java分類下載網(wǎng)頁的文件,你轉(zhuǎn)載的這篇技術(shù)文章對我啟發(fā)很大,只是,好像你沒有轉(zhuǎn)載完,是么?希望下次你轉(zhuǎn)載的時(shí)候能注明轉(zhuǎn)載的網(wǎng)址,給我們更多的方便。再次表示感謝。  回復(fù)  更多評論
            
          # re: [轉(zhuǎn)]利用Java編寫HTML文件分析程序 2007-09-04 16:06 | yslin_1985
          另外,哥們兒是Beyond的fans吧?me too.  回復(fù)  更多評論
            
          # re: [轉(zhuǎn)]利用Java編寫HTML文件分析程序 2007-09-22 23:26 | Alpha

          @yslin_1985
          呵呵,黃家駒忠實(shí)FANS,一生不變~!


            回復(fù)  更多評論
            
          主站蜘蛛池模板: 土默特右旗| 新余市| 陆良县| 苍南县| 潞城市| 玛沁县| 昌宁县| 抚远县| 若尔盖县| 津南区| 溧水县| 庐江县| 九江市| 乐安县| 盘锦市| 中阳县| 东光县| 师宗县| 临湘市| 邳州市| 杂多县| 宁乡县| 凌源市| 循化| 贵港市| 库伦旗| 千阳县| 湖北省| 沙雅县| 济宁市| 马公市| 昆明市| 乌兰浩特市| 海丰县| 宁城县| 彰武县| 霍州市| 泉州市| 五河县| 庆元县| 洮南市|