本文阐述如何利用 HTMLParser 项目对 HTML 或者 WML 文档中出现的一些特殊的或者是自定义的标签进行处理。
HTMLParser 是一个用来解析 HTML 文档的开放源码项目,它具有小巧、快速、使用简单的特点以及拥有强大的功能。对该项目还不了解的朋友可以参照 2004 年三月份我发表的文章--《从HTML中攫取你所需的信息》,这篇文章介绍如何通过 HTMLParser 来提取 HTML 文档中的文本数据以及提取出文档中的所有链接或者是图片等信息。
现在该项目的最新版本是 Integration Build 1.6,与之前版本的差别在于代码结构的调整、当然也有一些功能的提升以及 BugFix,同时对字符集的处理也更加自动了。比较遗憾的该项目并没有详尽的使用文档,你只能借助于它的 API 文档、一两个简单例子以及源码来熟悉它。
如果是 HTML 文档,那么用 HTMLParser 已经差不多可以满足你至少 90% 的需求。一个 HTML 文档中可能出现的标签差不多在 HTMLParser 中都有对应的类,甚至包括一些动态的脚本标签,例如 <%...%> 这种 JSP 和 ASP 用到的标签都有相应的 JspTag 对应。HTMLParser 的强大功能还体现在你可以修改每个标签的属性或者它所包含的文本内容并生成新的 HTML 文档,比如你可以文档中的链接地址偷偷的改成你自己的地址等等。关于 HTMLParser 的强大功能,其实上一篇文章已经介绍很多,这里不再累赘,我们今天要讲的是另外一个用途--处理自定义标签。
首先我们先解释一下什么叫自定义标签,我把所有不是 HTML 脚本语言中定义的标签称之为自定义标签,比如可以是 <scriptlet>、<book> 等等,这是我们自己创造出来的标签。你可能会很奇怪,因为这些标签一旦用在 HTML 文档中是没有任何效果的,那么我们换另外一个例子,假如你要解析的不是 HTML 文档,而是一个 WML(Wireless Markup Lauguage)文档呢?WML 文档中的 card,anchor 等标签 HTMLParser 是没有现成的标签类来处理的。还有就是你同样可以用 HTMLParser 来处理 XML 文档,而 XML 文档中所有的标签都是你自己定义的。
为了使我们的例子更具有代表意义,接下来我们将给出一段代码用来解析出 WML 文档中的所有链接,了解 WML 文档的人都知道,WML 文档中除了与 HTML 文档相同的链接写法外,还多了一种标签叫 <anchor>,例如在一个 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 的链接用来提交一个表单。) 如果我们还是使用 LinkTag 来遍历整个 WML 文档的话,那 Anchor 中的链接将会被我们所忽略掉。
下面我们先给出一个简单的例子,然后再叙述其中的道理。这个例子包含两个文件,一个是WML 的测试脚本文件 test.wml,另外一个是 Java 程序文件 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\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. 静态属性lnkFilter:这是一个NodeFilter的匿名类所构造的实例。该实例用来传递给HTMLParser告知需要提取哪些节点。在这个例子中我们仅需要提取链接标签以及我们自定义的一个GO标签。
3. 嵌套类WmlGoTag:这也是最为重要的一部分,这个类用来告诉HTMLParser如何去解析<go>这样一个节点。我们先看看下面这个HTMLParser的节点类层次图:
如上图所示,HTMLParser将一个文档分成三种节点分别是:Remark(注释);Text(文本);Tag(标签)。而标签又分成两种分别 是简单标签(Tag)和复合标签(CompositeTag),像<img><br/>这种标签称为简单标签,因为标签不会再包 含其它内容。而像<a href="xxxx">Home</a>这种类型的标签,因为标签会嵌套文本或者其他标签的称为复合标签,也就是对应着 CompositeTag这个类。简单标签的实现类很简单,只需要扩展Tag类并覆盖getIds方法以返回标签的识别文本,例如<img> 标签应该返回包含"img"字符串的数组,具体的代码可以参考HTMLParser自带的ImageTag标签类的实现。
从上图可清楚看出,复合标签事实上是对简单标签的扩展,HTMLParser在处理一个复合标签时需要知道该标签的起始标识以及结束标识,也就是我 们在前面给出的源码中的两个方法getIds和getEnders,一般来讲,标签出现都是成对的,因此这两个方法一般返回相同的值。另外一个方法 getEndTagEnders,这个方法用来返回父一级的标签名称,例如<tr>的父一级标签应该是<table>。这个方法 的必要性在于HTML对格式的要求很不严格,在很多的HTML文档中的一些标签经常是有开始标识,但是没有结束标识,由于浏览器的超强适应能力使这种情况 出现的很频繁,因此HTMLParser利用这个方法来辅助判断一个标签是否已经结束。由于WML文档的格式要求非常严格,因此上例源码中的 getEndTagEnders方法事实上可有可无。
4. 入口方法main:该方法初始化HTMLParser并注册新的节点解析器,解析文档并打印运行结果。
最后我们编译并运行这个例子,便可以得到下面的运行结果:
GO: /wap/user.do
LINK: /wap/index.vm
|
HTMLParser本身就是一个开放源码的项目,它对于HTML文档中出现的标签定义已经应有尽有,我们尽可以参考这些标签解析类的源码来学习如何实现一个标签的解析类,从而扩展出更丰富多彩的应用程序。
HTMLParser http://htmlparser.sourceforge.net/
分享到:
相关推荐
资源名称:扩展HTMLParser对自定义标签的处理能力内容简介: HTMLParser是一个用来解析HTML文档的开放源码项目,它具有小巧、快速、使用简单的特点以及拥有强大的功能。 现在该项目的最新版本是Integration Build ...
Java 程序在解析HTML 文档时,相信大家都接触过htmlparser 这个开源项目,我曾经在IBM DW 上发表过两篇关于htmlparser 的文章,分别是:从HTML中攫取你所需的信息 和扩展HTMLParser 对自定义标签的处理能力。...
Java 程序在解析HTML 文档时,相信大家都接触过htmlparser 这个开源项目,我曾经在IBM DW 上发表过两篇关于htmlparser 的文章,分别是:从HTML中攫取你所需的信息 和扩展HTMLParser 对自定义标签的处理能力。...
Java 程序在解析HTML 文档时,相信大家都接触过htmlparser 这个开源项目,我曾经在IBM DW 上发表过两篇关于htmlparser 的文章,分别是:从HTML中攫取你所需的信息 和扩展HTMLParser 对自定义标签的处理能力。...
为了解决这个问题,我们需要对HtmlParser进行扩展,增加对未知或自定义标签的支持。扩展HtmlParser通常包括以下几个步骤: 1. **注册新标签**:编写代码来注册自定义或不常见标签,使HtmlParser能够识别它们。这...
2. **自定义标签处理**:一个独特的特性是它支持处理自定义的HTML标签,这对于解析包含非标准标签或者XHTML文档特别有用。 3. **事件驱动模型**:解析器采用事件驱动模型,当遇到HTML元素、属性或其他结构时,会...
5. **可扩展性**:用户可以通过实现自定义的事件处理器来扩展HTMLParser的功能,以适应特定的解析需求。例如,可以创建一个处理器来提取所有的链接,或者查找特定的关键词。 6. **API友好**:HTMLParser的API设计...
6. **错误处理**:HTMLParser具有一定的容错能力,可以处理不完全符合HTML标准的文档,这对处理互联网上的HTML内容尤其有用。 在实际应用中,你可能需要将HTMLParser用于以下场景: - **数据抓取**:从网页中提取...
以下是对HTMLParser及其相关知识点的详细说明: 1. HTML解析:HTMLParser的设计目的是为了处理HTML文档的非结构化特性。由于HTML经常存在不规范的情况,如缺少闭合标签、嵌套错误等,HTMLParser通过容错机制,能够...
3. **标签处理**:HTMLParser支持自定义标签处理器。你可以为每一个HTML标签编写处理类,指定在遇到该标签时如何处理。这在需要对特定标签进行特殊操作时非常有用。 4. **解析结果的树形结构**:HTMLParser可以将...
7. **与其他库的集成**:HTMLParser可以轻松地与Java集合框架、XPath、DOM以及其他Java库结合使用,扩展其功能,如XML处理或数据分析。 在实际使用中,开发者通常会通过以下步骤使用HTMLParser: 1. **导入库**:...
- **标签和属性处理**:HTMLParser支持识别和处理HTML标签及其属性,可以提取特定标签内的文本或者根据属性筛选元素。 - **错误处理**:HTML文档通常不规范,HTMLParser具备一定的容错能力,能够处理一些常见的语法...
7. **自定义扩展**:拥有源码意味着我们可以根据需求对HTMLParser进行扩展,添加新的功能,比如增加新的选择器支持,优化性能,或者增强错误处理能力。 8. **集成测试**:虽然没有明确提及,但是一个成熟的库往往会...
**HtmlParser 2.1 知识点详解** HtmlParser是一个强大的开源库,主要用于解析HTML文档,它在处理不规则的HTML结构时表现出了极高的灵活性和...结合源代码学习,更能深入了解其内部机制,为自定义扩展和优化提供可能。
4. **可扩展性**:通过过滤器机制,开发者可以轻松添加自定义逻辑,根据需求对HTML内容进行处理。 5. **文档支持**:丰富的API文档使得开发者能够快速上手,解决在实际项目中遇到的问题。 总的来说,HTMLParser2.0...
HTMLParser库的优势在于其对HTML不规则性的容忍度,它可以处理嵌套不正确、缺失闭合标签等常见问题。此外,它还支持XML和SGML,扩展了其应用范围。 在提供的压缩文件中,有两个版本: - `htmlparser1_6_20060610....
3. **错误处理**:HTMLParser对HTML的非标准写法有很好的容错性,它能够处理不闭合的标签、缺失的引号等常见问题,确保在不规范的HTML文档中也能正常工作。 4. **标签和属性处理**:HTMLParser提供了丰富的API来...
HTMLParser是一个用于解析HTML文档的库,它使得开发者能够方便地获取网页的原始代码,并对网页数据进行深入的分析和处理。在Web开发中,HTMLParser对于自动化抓取、信息提取以及网页爬虫等任务非常有用。下面我们将...
7. **可扩展性**:通过自定义事件处理器,开发者可以根据需求扩展HTMLParser的功能,处理特定的HTML结构或者实现更复杂的逻辑。 8. **错误处理**:在解析过程中遇到问题时,HTMLParser2.0提供了良好的错误处理机制...
虽然HTMLParser本身并不直接提供这些功能,但可以通过扩展其API或者与其他库(如Jsoup)结合来实现。对于冲突的地方,描述中提到已经进行了修正,这意味着这个版本的jar包可能是开发者针对特定问题进行了优化的版本...