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

          ?1???????? import?java.io.*;?
          ?2  import?java.lang.String;?
          ?3  class?HtmlTokenizer?extends?
          ?4  StreamTokenizer?{?
          ?5  //定義各標記,這里的標記僅是本例中必須的,?
          ?6  可根據需要自行擴充?
          ?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;?//判斷是否在標記之中?
          16  ?
          17  ?//構造器,定義該令牌流的語法表。?
          18  ?public?HtmlTokenizer(BufferedReader?r)?{?
          19  super(r);?
          20  this.resetSyntax();?//重置語法表?
          21  this.wordChars(0,255);?//令牌范圍為全部字符?
          22  this.ordinaryChar('<?');?//HTML標記兩邊的分割符?
          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?'<?':?//進入標記字段?
          34  outsideTag=false;?
          35  return?nextHtml();?
          36  case?'>':?//出標記字段?
          37  outsideTag=true;?
          38  return?nextHtml();?
          39  case?StreamTokenizer.TT_WORD:?
          40  //若當前令牌為單詞,判斷是哪個標記?
          41  if?(allWhite(sval))?
          42  ?return?nextHtml();?//過濾其中空格?
          43  else?if(sval.toUpperCase().indexOf("FRAME")?
          44  !=-1?&&?!outsideTag)?//標記FRAME?
          45  ?return?HTML_FRAME;?
          46  else?if(sval.toUpperCase().indexOf("IMG")?
          47  !=-1?&&?!outsideTag)?//標記IMG?
          48  ?return?HTML_IMAGE;?
          49  else?if(sval.toUpperCase().indexOf("BACKGROUND")?
          50  !=-1?&&?!outsideTag)?//標記BACKGROUND?
          51  ?return?HTML_BACKGROUND;?
          52  else?if(sval.toUpperCase().indexOf("APPLET")?
          53  !=-1?&&?!outsideTag)?//標記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  //實現略?
          66  ?}
          //?end?of?allWhite?
          67  ?
          68  }
          ?//end?of?class?
          69


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

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

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


            回復  更多評論
            
          主站蜘蛛池模板: 阿拉善右旗| 五指山市| 淳安县| 濉溪县| 任丘市| 曲松县| 喀喇沁旗| 定兴县| 新安县| 碌曲县| 青河县| 云梦县| 临澧县| 日喀则市| 台北县| 和龙市| 鸡西市| 红桥区| 甘肃省| 永川市| 兖州市| 海门市| 壶关县| 桑日县| 钟山县| 广水市| 石家庄市| 峨眉山市| 铜鼓县| 潼关县| 昆山市| 保靖县| 阿合奇县| 郸城县| 华亭县| 三河市| 石楼县| 平泉县| 台州市| 宁波市| 彰武县|