사용자 정의 태그에 대한 HTMLParser 처리 능력 확장

본고는 HTMLParser 프로젝트를 이용하여 HTML이나 WML 문서에 나타난 특수하거나 사용자 정의 라벨을 어떻게 처리하는지 논술하고자 한다.
HTMLParser는 HTML 문서를 분석하는 데 사용되는 오픈 소스 프로젝트로 작고 빠르며 사용이 간단하며 강력한 기능을 가지고 있다.이 프로젝트에 대해 잘 모르시는 분들은 2004년 3월에 제가 발표한 글인 을 참조하시면 됩니다.이 글은 HTMLParser를 통해 HTML 문서의 텍스트 데이터를 추출하고 문서의 모든 링크나 그림을 추출하는 방법을 소개한다.
현재 이 프로젝트의 최신 버전은Integration Build 1.6이다. 이전 버전과 다른 것은 코드 구조의 조정, 물론 일부 기능의 향상과 BugFix이며 문자 집합에 대한 처리도 더욱 자동화되었다.비교적 유감스러운 이 프로젝트는 문서를 상세하게 사용하지 않았기 때문에, 당신은 그것의 API 문서, 한두 개의 간단한 예와 원본 코드를 빌려 그것을 익힐 수 있을 뿐이다.
HTML 문서라면, HTMLParser를 사용하면 최소한 90퍼센트의 요구를 충족시킬 수 있을 것이다.HTML 문서에 나타날 수 있는 탭의 차이는 HTMLParser에 대응하는 클래스가 많지 않으며, 심지어는 동적 스크립트 탭도 포함된다. 예를 들어 <%...% >이 JSP와 ASP가 사용하는 태그는 해당 JspTag에 해당합니다.HTMLParser의 강력한 기능은 모든 탭의 속성이나 그 안에 포함된 텍스트 내용을 수정하고 새로운 HTML 문서를 만들 수 있다. 예를 들어 문서의 링크 주소를 몰래 자신의 주소로 바꿀 수 있다.HTMLParser의 강력한 기능에 관해서는 사실 지난 글에서 이미 많은 것을 소개했는데, 여기는 더 이상 군더더기가 없다. 우리가 오늘 말하고자 하는 것은 또 다른 용도인 사용자 정의 라벨을 처리하는 것이다.
먼저 사용자 정의 라벨이 무엇인지 설명해 봅시다. HTML 스크립트 언어에서 정의되지 않은 모든 라벨을 사용자 정의 라벨이라고 합니다. 예를 들어 , 등입니다. 이것은 우리가 창조한 라벨입니다.이 태그들이 HTML 문서에 사용되면 아무런 효과가 없기 때문에 이상할 수도 있습니다. 만약 당신이 해석하고자 하는 것이 HTML 문서가 아니라 WML (Wireless Markup Lauguage) 문서라면?WML 문서의 카드, anchor 등 라벨 HTMLParser는 기존의 라벨 종류로 처리되지 않습니다.그리고 HTMLParser로도 XML 문서를 처리할 수 있으며, XML 문서의 모든 탭은 당신이 정의한 것입니다.
우리의 예를 더욱 대표적인 의미를 가지기 위해서 다음에 우리는 WML 문서의 모든 링크를 해석하는 코드를 제시할 것이다. WML 문서를 아는 사람들은 WML 문서에 HTML 문서와 같은 링크 쓰기 외에 라는 라벨이 더 많다는 것을 안다. 예를 들어 WML 문서에서 우리는 다음과 같은 두 가지 방식으로 링크를 나타낼 수 있다.
 
<a href="http://www.javayou.com?cat_id=1">Java   </a>
  :
<anchor>
Java   
    <go href="http://www.javayou.com" method="get">
        <postfield name="cat_id" value="1"/>
</go>
</anchor>

 
(더 많은 경우 anchor 링크를 사용하여 폼을 제출합니다.)만약 우리가 링크태그를 사용하여 전체 WML 문서를 훑어본다면, Anchor의 링크는 무시될 것입니다.
다음에 우리는 먼저 간단한 예를 제시한 다음에 그 중의 이치를 서술한다.이 예는 두 개의 파일을 포함하는데, 하나는 WML의 테스트 스크립트 파일test입니다.wml, 다른 하나는 자바 프로그램 파일 HyperLinkTrace입니다.java, 내용은 다음과 같습니다.
 
<?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>    
		<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의 굵은 부분은 우리가 추출해야 할 링크입니다.
 
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);
		//           
		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
"); 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. 정적 속성 lnkFilter: NodeFilter의 익명 클래스로 구성된 예입니다.이 인스턴스는 HTMLParser에 전달하여 추출할 노드를 알려줍니다.이 예에서 우리는 링크 탭과 우리가 정의한 GO 탭만 추출해야 한다.
3. 플러그인 클래스 WmlGoTag: 이것도 가장 중요한 부분이다. 이 클래스는 HTMLParser가 와 같은 노드를 어떻게 해석하는지 알려주는 데 사용된다.먼저 다음 HTMLParser의 노드 클래스 계층도를 살펴보겠습니다.
위의 그림에서 보듯이 HTMLParser는 문서를 세 가지 노드로 나눈다. 그것이 바로 Remark(주석)이다.텍스트태그.라벨은 두 가지로 나뉘는데 그것이 바로 단순 라벨(Tag)과 복합 라벨(CompositeTag)이다. 예를 들어
와 같은 라벨은 단순 라벨이라고 부른다. 라벨은 다른 내용을 포함하지 않기 때문이다.한편, Home와 같은 유형의 라벨은 라벨에 텍스트나 다른 라벨을 끼워서 복합 라벨이라고 하는데 바로CompositeTag과 대응하기 때문이다.간단한 탭의 실현 클래스는 매우 간단합니다. 태그 클래스를 확장하고 getIds 방법을 덮어써서 탭의 식별 텍스트를 되돌려줍니다. 예를 들어 탭은'img'문자열을 포함하는 그룹을 되돌려야 합니다. 구체적인 코드는 HTMLParser가 자체로 가지고 있는 ImageTag 탭 클래스의 실현을 참고할 수 있습니다.
위의 그림에서 알 수 있듯이 복합 라벨은 사실상 간단한 라벨에 대한 확장이다. HTMLParser는 복합 라벨을 처리할 때 이 라벨의 시작 표지와 끝 표지, 즉 우리가 앞에서 제시한 원본 코드 중의 두 가지 방법인 getIds와 getEnders를 알아야 한다. 일반적으로 라벨이 나타나는 것은 모두 쌍이기 때문에 이 두 가지 방법은 일반적으로 같은 값을 되돌려준다.다른 방법은 getEndTagEnders입니다. 이 방법은 부모의 탭 이름을 되돌려줍니다. 예를 들어 의 부모 탭은 이어야 합니다.이 방법의 필요성은 HTML이 형식에 대한 요구가 엄격하지 않다는 데 있다. 많은 HTML 문서에서 일부 라벨은 시작 표지가 있지만 끝 표지가 없다. 브라우저의 강력한 적응 능력으로 이런 상황이 빈번하게 나타나기 때문에 HTMLParser는 이 방법을 이용하여 라벨이 끝났는지 아닌지를 보조적으로 판단한다.WML 문서의 형식 요구가 매우 엄격하기 때문에, 상기 원본 코드의 getEndTagEnders 방법은 사실상 있어도 되고 없어도 된다.
4. 입구 방법main: 이 방법은 HTMLParser를 초기화하고 새로운 노드 해상도를 등록하여 문서를 분석하고 실행 결과를 출력합니다.
마지막으로 이 예를 컴파일하고 실행하면 다음 실행 결과를 얻을 수 있습니다.
 
GO: 	/wap/user.do
LINK: 	/wap/index.vm

 
HTMLParser 자체는 오픈 소스 프로젝트로 HTML 문서에 나타나는 탭에 대한 정의가 모두 갖추어져 있습니다. 이 탭 해석 클래스의 원본을 참고하여 탭의 해석 클래스를 어떻게 실현하는지 배워서 더욱 풍부하고 다채로운 응용 프로그램을 확장할 수 있습니다.
HTMLParser HTML에서 당신이 필요로 하는 정보를 빼앗다

좋은 웹페이지 즐겨찾기