打印本頁將此頁作為電子郵件發(fā)送

日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

擴展 HTMLParser 對自定義標簽的處理能力

系統(tǒng) 2910 0
文檔選項
<script type="text/javascript"></script> <noscript></noscript> <script type="text/javascript"></script> <noscript></noscript>
將打印機的版面設置成橫向打印模式

打印本頁

將此頁作為電子郵件發(fā)送

將此頁作為電子郵件發(fā)送

<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- this content will be automatically generated across all content areas --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

級別: 初級

冬 劉 ( javayou@gmail.com ), 廣州市摩網信息技術有限公司技術副總經理

2006 年 4 月 13 日

本文闡述如何利用 HTMLParser 項目對 HTML 或者 WML 文檔中出現(xiàn)的一些特殊的或者是自定義的標簽進行處理。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

HTMLParser 是一個用來解析 HTML 文檔的開放源碼項目,它具有小巧、快速、使用簡單的特點以及擁有強大的功能。對該項目還不了解的朋友可以參照 2004 年三月份我發(fā)表的文章--《 從HTML中攫取你所需的信息 》,這篇文章介紹如何通過 HTMLParser 來提取 HTML 文檔中的文本數(shù)據(jù)以及提取出文檔中的所有鏈接或者是圖片等信息。

現(xiàn)在該項目的最新版本是 Integration Build 1.6,與之前版本的差別在于代碼結構的調整、當然也有一些功能的提升以及 BugFix,同時對字符集的處理也更加自動了。比較遺憾的該項目并沒有詳盡的使用文檔,你只能借助于它的 API 文檔、一兩個簡單例子以及源碼來熟悉它。

如果是 HTML 文檔,那么用 HTMLParser 已經差不多可以滿足你至少 90% 的需求。一個 HTML 文檔中可能出現(xiàn)的標簽差不多在 HTMLParser 中都有對應的類,甚至包括一些動態(tài)的腳本標簽,例如 <%...%> 這種 JSP 和 ASP 用到的標簽都有相應的 JspTag 對應。HTMLParser 的強大功能還體現(xiàn)在你可以修改每個標簽的屬性或者它所包含的文本內容并生成新的 HTML 文檔,比如你可以文檔中的鏈接地址偷偷的改成你自己的地址等等。關于 HTMLParser 的強大功能,其實上一篇文章已經介紹很多,這里不再累贅,我們今天要講的是另外一個用途--處理自定義標簽。

首先我們先解釋一下什么叫自定義標簽,我把所有不是 HTML 腳本語言中定義的標簽稱之為自定義標簽,比如可以是 <scriptlet>、<book> 等等,這是我們自己創(chuàng)造出來的標簽。你可能會很奇怪,因為這些標簽一旦用在 HTML 文檔中是沒有任何效果的,那么我們換另外一個例子,假如你要解析的不是 HTML 文檔,而是一個 WML(Wireless Markup Lauguage)文檔呢?WML 文檔中的 card,anchor 等標簽 HTMLParser 是沒有現(xiàn)成的標簽類來處理的。還有就是你同樣可以用 HTMLParser 來處理 XML 文檔,而 XML 文檔中所有的標簽都是你自己定義的。

為了使我們的例子更具有代表意義,接下來我們將給出一段代碼用來解析出 WML 文檔中的所有鏈接,了解 WML 文檔的人都知道,WML 文檔中除了與 HTML 文檔相同的鏈接寫法外,還多了一種標簽叫 <anchor>,例如在一個 WML 文檔我們可以用下面兩種方式來表示一個鏈接。

?

            <a >Java自由人</a>
或者:
<anchor>
Java自由人
    <go  method="get">
        <postfield name="cat_id" value="1"/>
</go>
</anchor>

          

?

(更多的時候使用 anchor 的鏈接用來提交一個表單。) 如果我們還是使用 LinkTag 來遍歷整個 WML 文檔的話,那 Anchor 中的鏈接將會被我們所忽略掉。

下面我們先給出一個簡單的例子,然后再敘述其中的道理。這個例子包含兩個文件,一個是WML 的測試腳本文件 test.wml,另外一個是 Java 程序文件 HyperLinkTrace.java,內容如下:

?




回頁首


1. test.wml

?

            <?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card title="Java自由人登錄">
<p>  
	用戶名:<input type="text" name="username" size="15"/>
     密碼:<input type="text" name="password" size="15"/>
	<br/>
	<anchor>現(xiàn)在登錄
		<go href="/wap/user.do" method="get">
    		<postfield name="name" value="$(username)"/>
    		<postfield name="password" value="$(password)"/>
    		<postfield name="eventSubmit_Login" value="WML"/>
		</go>
	</anchor><br/>
	<a href="/wap/index.vm">返回首頁</a>
</p>
</card>
</wml>

          

?

test.wml 中的粗體部分是我們需要提取出來的鏈接。

?




回頁首


2. HyperLinkTrace.java

?

            package demo.htmlparser;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.URL;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.PrototypicalNodeFactory;
import org.htmlparser.tags.CompositeTag;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
/**
 * 用來遍歷WML文檔中的所有超鏈接
 * @author Winter Lau
 */
public class HyperLinkTrace {
	public static void main(String[] args) throws Exception {
		//初始化HTMLParser
		Parser parser = new Parser();
		parser.setEncoding("8859_1");
		parser.setInputHTML(getWmlContent());
		
		//注冊新的結點解析器
		PrototypicalNodeFactory factory = new PrototypicalNodeFactory ();
		factory.registerTag(new WmlGoTag ());
		parser.setNodeFactory(factory);
		//遍歷符合條件的所有節(jié)點
		NodeList nlist = parser.extractAllNodesThatMatch(lnkFilter);
		for(int i=0;i<nlist.size();i++){
			CompositeTag node = (CompositeTag)nlist.elementAt(i);
			if(node instanceof LinkTag){
				LinkTag link = (LinkTag)node;
				System.out.println("LINK: \t" + link.getLink());
			}
			else if(node instanceof WmlGoTag){
				WmlGoTag go = (WmlGoTag)node;
				System.out.println("GO: \t" + go.getLink());
			}
		}
	}
	/**
	 * 獲取測試的WML腳本內容
	 * @return
	 * @throws Exception
	 */
	static String getWmlContent() throws Exception{
		URL url = ParserTester.class.getResource("/demo/htmlparser/test.wml");
		File f = new File(url.toURI());
		BufferedReader in = new BufferedReader(new FileReader(f));
		StringBuffer wml = new StringBuffer();
		do{
			String line = in.readLine();
			if(line==null)
				break;
			if(wml.length()>0)
				wml.append("\r\n");
			wml.append(line);			
		}while(true);
		return wml.toString();		
	}
	/**
	 * 解析出所有的鏈接,包括行為<a>與<go>
	 */
	static NodeFilter lnkFilter = new NodeFilter() {
		public boolean accept(Node node) {
			if(node instanceof WmlGoTag)
				return true;
			if(node instanceof LinkTag)
				return true;
			return false;
		}
	};
	
	/**
	 * WML文檔的GO標簽解析器
	 * @author Winter Lau
	 */
	static class WmlGoTag extends CompositeTag {
	    private static final String[] mIds = new String[] {"GO"};
	    private static final String[] mEndTagEnders = new String[] {"ANCHOR"};
	    public String[] getIds (){
	        return (mIds);
	    }
	    public String[] getEnders (){
	        return (mIds);
	    }
	    public String[] getEndTagEnders (){
	        return (mEndTagEnders);
	    }
	    
	    public String getLink(){
	    	return super.getAttribute("href");
	    }
	    
	    public String getMethod(){
	    	return super.getAttribute("method");
	    }
	}
}

          

?

上面這段代碼比較長,可以分成下面幾部分來看:

1. getWmlContent方法: 該方法用來獲取在同一個包中的test.wml腳本文件的內容并返回字符串。

2. 靜態(tài)屬性lnkFilter:這是一個NodeFilter的匿名類所構造的實例。該實例用來傳遞給HTMLParser告知需要提取哪些節(jié)點。在這個例子中我們僅需要提取鏈接標簽以及我們自定義的一個GO標簽。

3. 嵌套類WmlGoTag:這也是最為重要的一部分,這個類用來告訴HTMLParser如何去解析<go>這樣一個節(jié)點。我們先看看下面這個HTMLParser的節(jié)點類層次圖:


如上圖所示,HTMLParser將一個文檔分成三種節(jié)點分別是:Remark(注釋);Text(文本);Tag(標簽)。而標簽又分成兩種分別是簡單標簽(Tag)和復合標簽(CompositeTag),像<img><br/>這種標簽稱為簡單標簽,因為標簽不會再包含其它內容。而像<a href="xxxx">Home</a>這種類型的標簽,因為標簽會嵌套文本或者其他標簽的稱為復合標簽,也就是對應著CompositeTag這個類。簡單標簽的實現(xiàn)類很簡單,只需要擴展Tag類并覆蓋getIds方法以返回標簽的識別文本,例如<img>標簽應該返回包含"img"字符串的數(shù)組,具體的代碼可以參考HTMLParser自帶的ImageTag標簽類的實現(xiàn)。

從上圖可清楚看出,復合標簽事實上是對簡單標簽的擴展,HTMLParser在處理一個復合標簽時需要知道該標簽的起始標識以及結束標識,也就是我們在前面給出的源碼中的兩個方法getIds和getEnders,一般來講,標簽出現(xiàn)都是成對的,因此這兩個方法一般返回相同的值。另外一個方法getEndTagEnders,這個方法用來返回父一級的標簽名稱,例如<tr>的父一級標簽應該是<table>。這個方法的必要性在于HTML對格式的要求很不嚴格,在很多的HTML文檔中的一些標簽經常是有開始標識,但是沒有結束標識,由于瀏覽器的超強適應能力使這種情況出現(xiàn)的很頻繁,因此HTMLParser利用這個方法來輔助判斷一個標簽是否已經結束。由于WML文檔的格式要求非常嚴格,因此上例源碼中的getEndTagEnders方法事實上可有可無。

4. 入口方法main:該方法初始化HTMLParser并注冊新的節(jié)點解析器,解析文檔并打印運行結果。

最后我們編譯并運行這個例子,便可以得到下面的運行結果:

?

            GO: 	/wap/user.do
LINK: 	/wap/index.vm

          

?

HTMLParser本身就是一個開放源碼的項目,它對于HTML文檔中出現(xiàn)的標簽定義已經應有盡有,我們盡可以參考這些標簽解析類的源碼來學習如何實現(xiàn)一個標簽的解析類,從而擴展出更豐富多彩的應用程序。


參考資料

擴展 HTMLParser 對自定義標簽的處理能力


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 镇康县| 石狮市| 盐津县| 莎车县| 富民县| 乌什县| 连江县| 鄯善县| 榆中县| 蓬安县| 康保县| 福清市| 商都县| 麻江县| 富平县| 广南县| 邳州市| 德化县| 桦甸市| 桃园市| 上杭县| 拜城县| 宝鸡市| 基隆市| 盐津县| 东宁县| 略阳县| 礼泉县| 博乐市| 遵义市| 延津县| 衡山县| 七台河市| 龙山县| 双牌县| 桦南县| 揭阳市| 确山县| 庐江县| 巴青县| 醴陵市|