您的位置:首页 > Web前端 > HTML

HtmlAgilityPack的一点总结

2013-12-21 21:33 260 查看
最近工作中用到了HtmlAgilityPack的类库,总的来说使用起来确实感觉挺方便,别的不多说,就这类似于能把HTML标签自动补全的Load()方法就感觉挺赞(其实上不是不全,而是将不完整的标签给格式化一下)。但这不就足够了吗?舍得自己去用正则表达式去匹配,万一匹配的内容就是HTML作者写的文本内容,岂不功亏一篑。

不废话,使用的时候加载HtmlAgilityPack.dll(下载去官网),using HtmlAgilityPack; 就可以使用[b]HtmlAgilityPack了。[/b]

本文以格式化一篇Html为例,讲述一点此类库的一点用法,至于更多的方法和属性,那就看作者的发挥了。

何为格式化HTML?当你看到别人写的HTML是这样的:

<html><head><title>就是一个字符串</title></head><body><p>就是不换行</p></body></html>

是不是觉得很头疼呢?写成规范一点的树结构是不是更好一点?(虽然改变了原文,加入了很多/r,/n,/t,但毕竟这是用户想看到的)

[b]<html>[/b]

[b]______<head>[/b]

[b]______[b]______[/b][/b]<title>

______[b]______[b]______[/b][/b]就是一个字符串

[b]______[b]______[/b][/b]</title>

______</head>

______<body>

[b]______[b]______[/b][/b]<p>

______[b]______[b]______[/b][/b]就是不换行

[b]______[b]______[/b][/b]</p>

[b][b]______[/b][/b]</body>

</html>

当然了,强大的IDE和各种工具会帮你做到,但是!实际开发中怎会容你轻松的使用其他非开源工具,而开元的HTMLAgility区区几行代码便能做到。

不多说,上代码:



private HtmlDocument loadWebSi
b471
te(string path)
{
HtmlDocument hDoc = new HtmlDocument();//整片html文档对象
if (File.Exists(path))
{
hDoc.Load(path, Encoding.Default);
hDoc.LoadHtml(hDoc.DocumentNode.OuterHtml);//load两边是为了保证标签的完整性,DocumentNode代表文档节点							     						     (文档的开头了结尾,不一定是<html>,OuterHtml代表此nod	e的html文本)
}
return hDoc;
}
计算父节点的方法,以<html>节点为根父节点,有所少个父节点,就加入多少个/t(缩进)
private int parentNumbers(HtmlNode node, int temp)
{
int result = temp;
if (node.ParentNode != null)
{
if (node.ParentNode.Name.Equal("html"))
{
return result;
}
else
{
result = result + parentNumbers(node.ParentNode, 1);//递归调用
}
}
return result;
}
好了,以上两个方法是准备工作,真正格式化的方法在这里:



private void convertHTML(string filePath)
{
HtmlDocument hDoc = loadWebSite(filePath);
string reg = "\\S+";
Regex regex = new Regex(reg, RegexOptions.IgnoreCase);//此处的正则表达式是为了将html文件写成一行,将原作者的转义字符取消,加入自己的转义字符(/r/n/t)
HtmlNodeCollection htmlNodeCollection = hDoc.DocumentNode.SelectNodes("/html");
StringBuilder htmlContent = new StringBuilder();

if (htmlNodeCollection.Count() > 0)
{
foreach (HtmlNode htmlNode in htmlNodeCollection)
{
foreach (HtmlNode hNode in htmlNode.Descendants().Where(n => n.NodeType == HtmlNodeType.Text))
{
Match match = regex.Match(hNode.OuterHtml);
if (match.Success == false)
{
hNode.InnerHtml = string.Empty;
}
else
{
hNode.InnerHtml = hNode.InnerHtml.Trim();
}
}
htmlContent.Append(htmlNode.OuterHtml);
}
}
else { throw new Exception("Document Have No Html Element"); }
//load两遍,保证标签的完整性
hDoc.LoadHtml(htmlContent.ToString());
StringBuilder content = new StringBuilder(hDoc.DocumentNode.OuterHtml);
hDoc.LoadHtml(content.ToString());
HtmlNodeCollection lineCollection = hDoc.DocumentNode.SelectNodes("/html");
Dictionary<int, string> insContent = new Dictionary<int, string>();//key为要插入的index,value为插入的内容,也就是/r/n, /r/n/t, /r/n/t/t.../t
StringBuilder tempBuilder = new StringBuilder();

foreach (HtmlNode htmlNode in lineCollection)
{
insContent.Add(htmlNode.StreamPosition, "\r\n");
if (htmlNode.HasChildNodes)
{
insContent.Add(htmlNode.FirstChild.StreamPosition, "\r\n\t");
insContent.Add(htmlNode.LastChild.StreamPosition + htmlNode.LastChild.OuterHtml.Length, "\r\n");
}
foreach (HtmlNode hNode in htmlNode.Descendants())//遍历所有子代节点
{
if (hNode.ParentNode.Name.Eq("style"))//此处的判断是针对HTMLAgility的一个Bug,当节点为<style>时,此节点的StreamPosition为0,这是不对的,正确值应为对应							    的html字符串形式时的Index值
{
continue;
}
if (hNode.PreviousSibling != null)//上一个兄弟节点
{
if (!insContent.ContainsKey(hNode.StreamPosition))
{
tempBuilder.Remove(0, tempBuilder.Length);
tempBuilder.Append("\r\n");
for (int i = 0; i < parentNumbers(hNode, 1); i++)
{
tempBuilder.Append("\t");
}
insContent.Add(hNode.StreamPosition, tempBuilder.ToString());
}
}
if (hNode.NextSibling != null)//下一个兄弟节点
{
if (!insContent.ContainsKey(hNode.StreamPosition))
{
tempBuilder.Remove(0, tempBuilder.Length);
tempBuilder.Append("\r\n");
for (int i = 0; i < parentNumbers(hNode, 1); i++)
{
tempBuilder.Append("\t");
}
insContent.Add(hNode.NextSibling.StreamPosition, tempBuilder.ToString());
}
}
if (hNode.HasChildNodes)
{
if (hNode.FirstChild != null)//第一个子节点
{
if (!insContent.ContainsKey(hNode.FirstChild.StreamPosition))
{
tempBuilder.Remove(0, tempBuilder.Length);
tempBuilder.Append("\r\n");
for (int i = 0; i < parentNumbers(hNode.FirstChild, 1); i++)
{
tempBuilder.Append("\t");
}
insContent.Add(hNode.FirstChild.StreamPosition, tempBuilder.ToString());
}
}
if (hNode.LastChild != null)//最后一个子节点
{
if (!insContent.ContainsKey(hNode.LastChild.StreamPosition + hNode.LastChild.OuterHtml.Length))
{
tempBuilder.Remove(0, tempBuilder.Length);
tempBuilder.Append("\r\n");
for (int i = 0; i < parentNumbers(hNode, 1); i++)
{
tempBuilder.Append("\t");
}
insContent.Add(hNode.LastChild.StreamPosition + hNode.LastChild.OuterHtml.Length, tempBuilder.ToString());
}
}
}
}
}

foreach (KeyValuePair<int, string> item in insContent.OrderByDescending(n => n.Key))//倒序插入,保证原html不变
{
content.Insert(item.Key, item.Value);
}
File.WriteAllText(filePath, content.ToString(), Encoding.UTF8);
}
好了,以上方法能够实现格式化一篇html的功能了,经测试,新浪,搜狐,网易的门户网站的html已经格式化成功,其实作者也可以看看这些门户网站的html代码,那是多么的乱。针对于HTMLAgility的类库和方法介绍的并不算全面,但是以上这些获取节点集合,属性集合,innerHtml等等吧,还有HtmlWeb类都是最常用的,解析HTML我想足够了,就这些吧。



















































内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  标签 HTMLAgility C#