随笔-11  评论-39  文章-0  trackbacks-0
开始想先写PDF的内容显示,但是发现大家对HTML的解析更为感兴趣,所以我先写HTML的解析。
HTML的解析,很多人都会想着用IHTMLDocument这个内置对象来完成,但是我始终觉得这个是在COM的基础上来.NET,感觉不是很爽,同时它并不能完全满足我的要求,所以我自己实现这一过程。这个过程也许很多人认为是个很大的工程量,但是事实上,经过仔细的分析,并没有想象的那么复杂。最后我只用了三四个小时,三四百行的C#代码就实现了。
从功能上,我把HTML的解析分成了结构解析,和显示的外观解析,外观解析这个把它和PDF的生成放到一起,因为他们的关系很密切这里先说结构解析。从宏观上来看,HTML也是一种很类似于XML的一种格式,只是相对来说它的容错性上要好很多。所以HTML的解析事实上很容易就转化成了写一个有容错性的XML解析器。
HTML解析后的结构可以有多种,我比较喜欢DOM模型,所以我把他们往DOM模型方向去解析。熟悉HTML的人都知道,一个HTML标签可以分解成为以:一个标签名,若干个属性,具体的文本内容 这样的一种形式。所以抛开显示的因素去想,这时候整个HTML用这个模型就可以很容易地解析了个大概了,剩下的没有处理的就是style标签和style属性,还有外挂的样式文件。估计写得大家会比较晕,下面就来看我具体的解析过程。
首先是解析生成HTML节点树。在OO出现之前,描述节点树的数据结构还是比较复杂的,感觉要用个二维的树形结构,因为每个节点里会含多个属性,同时也会含有多个子节点,但是有了OO,很简单了,放两个ArrayList一个里面放属性对象,另一个放子节点。为了处理方便,我先用正则把里面的script块和注释块给替换掉了。下面的解析中,就是根据起始标签的<,>号去分解。至于容错,开始想是用迭代法来实现,也就是在前面找到一个标签后,到后面去找反标签,但是后来发现要处理的异常情况太多了,所以就放弃了。而使用堆栈的形式。每找到一个正标签,就把把它压栈,当找到一个封闭的标签的时候,就把它出栈,当然不能和栈顶的标签来匹配的时候,就会往下找,直到找到为止。事实上这个压栈的顺序就含着包含的关系,所以生成这个树的过程很容易就完成了。
其次就是属性的解析,因为HTML的高容错性,所以属性有多种情况,有单独的一个单词做属性如:checked,selected,readonly等,还有A=BA=“B” A=‘B’ 这三种形式,为了容易解析,这里用了一个正则来实现,为了方便大家的使用,就把它写出来了:((\\w+)=((\"[^\"]*\")|('[^']*')|([^\"^' ]+)))|readonly|checked|selected。对匹配后的结果进行分析,这样就完成了大部分的属性的解析。当然这里面还有一个STYLE块的解析的问题还没有解决,不过相对来说也不难,就是根据属性值里面的;号进行分割,然后再按:号来取样式的名称和值。
这样一个HTML解析过程基本上就完成了。
下一次我将写PDF的内容显示,也就是PostScript。
posted on 2006-01-13 17:14 铁匠 阅读(2009) 评论(2)  编辑 收藏

评论:
#1楼  2006-06-20 19:40 | whjwu [未注册用户]
我用java在写蜘蛛的时候,做了个很简单的HTMLpraser

主要代码为:
public String parserForLan(String str,String Token1, String Token2)
{
String parseStr="";

int i = 0;
int j = 0;
while(i < str.length() && (i+6) < str.length())
{
if(str.substring(i,i+6).equalsIgnoreCase(Token1))
{
parseStr = parseStr + str.substring(j,i);
i = i+6;
while(i < str.length() && (i+7) < str.length())
{
if(str.substring(i,i+7).equalsIgnoreCase(Token2))
{
i = i+7;
j = i;
break;
}
i++;
}

}
i++;
}
parseStr = parseStr + str.substring(j,i);
return parseStr;
}

public String parser(String str, char chF, char chB)
{
int i = 0;
int j = 0;
String parseStr = "";
while (i < str.length())
{
if(str.charAt(i) == chF)
{
i++;
while( i < str.length())
{
if(str.charAt(i) == chB)
{
i = i + 1;
j = i;
break;
}
i++;
}
}
while(i < str.length())
{
if(str.charAt(i) == chF)
{
parseStr = parseStr + str.substring(j, i) + " ";
break;
}
else i++;
}
}
ForI = i;
ForJ = j;
return parseStr;
}

public String parser1(String str, char chF, char chB)
{
String parseStr = parser(str, '&', ';');
parseStr = parseStr + str.substring(ForJ, ForI);
return parseStr;
}

public String allParser(String str)
{
String BeParseStr = parserForLan(str,"script","/script");
BeParseStr = parser(BeParseStr, '<', '>');
BeParseStr = parser1(BeParseStr, '&', ';');
return BeParseStr;
}

一般网页还好,但是遇到源代码如下的就不行了:
<img src="http://www.sjzdaily.com.cn/tplimg/xscj0021.gif"">http://www.sjzdaily.com.cn/tplimg/xscj0021.gif" border="0" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://www.sjzdaily.com.cn/tplimg/xscj0021.gif');}" onmousewheel="return imgzoom(this);">

因为在这中间有许多的">"号,所以简单的基于"<"">"对的删除失效了
不知道你有何见解?QQ185415255
  回复  引用    
#2楼  2006-07-20 10:55 | lizhi [未注册用户]
请问有没有C#写的html解析啊?
比如说:数据库里面有 : <input id="txtName" type="text" value="新增流程分类" /> 这一个 text 类型的数据!

现在,我需要写一段解析代码, 它可以解析到<> , input , id , 还有 value 里面的值等. 并在网页中显示出来!


大哥们,救救急啊!
万分感谢啊~~~
请发往邮箱: lizhi198304@163.com
  回复  引用    

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
 
另存  打印