HTML解析类 ,让你不使用正则也能轻松获取HTML相关元素 -C# .NET

功能:

1、轻松获取指元素HTML元素。

2、可以根据属性标签进行筛选

3、返回的都是Llist强类型无需转换

用过XElement的都知道 用来解析XML非常的方便,但是对于HTML的格式多样化实在是没办法兼容。

所以我就写了这么一个类似XElement的 XHTMLElement

用法:

            string filePath = Server.MapPath("~/file/test.htm");
            //获取HTML代码
            string mailBody = FileHelper.FileToString(filePath);

            XHtmlElement xh = new XHtmlElement(mailBody);

            //获取body的子集a标签并且class="icon"
            var link = xh.Descendants("body").ChildDescendants("a").Where(c => c.Attributes.Any(a => a.Key == "class" && a.Value == "icon")).ToList();

            //获取带href的a元素
            var links = xh.Descendants("a").Where(c => c.Attributes.Any(a => a.Key == "href")).ToList();
            foreach (var r in links)
            {
                Response.Write(r.Attributes.Single(c => c.Key == "href").Value); //出输href
            }

            //获取第一个img
            var img = xh.Descendants("img");

            //获取最近的第一个p元素以及与他同一级的其它p元素
            var ps = xh.Descendants("p");

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Text.RegularExpressions;

namespace SyntacticSugar
{
    /// <summary>
    /// ** 描述:html解析类
    /// ** 创始时间:2015-4-23
    /// ** 修改时间:-
    /// ** 作者:sunkaixuan
    /// ** qq:610262374 欢迎交流,共同提高 ,命名语法等写的不好的地方欢迎大家的给出宝贵建议
    /// </summary>
    public class XHtmlElement
    {
        private string _html;
        public XHtmlElement(string html)
        {
            _html = html;
        }

        /// <summary>
        /// 获取最近的相同层级的HTML元素
        /// </summary>
        /// <param name="elementName">等于null为所有元素</param>
        /// <returns></returns>
        public List<HtmlInfo> Descendants(string elementName = null)
        {
            if (_html == null)
            {
                throw new ArgumentNullException("html不能这空!");
            }
            var allList = RootDescendants(_html);
            var reval = allList.Where(c => elementName == null || c.TagName.ToLower() == elementName.ToLower()).ToList();
            if (reval == null || reval.Count == 0)
            {
                reval = GetDescendantsSource(allList, elementName);
            }
            return reval;
        }

        /// <summary>
        /// 获取第一级元素
        /// </summary>
        /// <param name="elementName"></param>
        /// <returns></returns>
        public List<HtmlInfo> RootDescendants(string html = null)
        {
            /*
             * 业务逻辑:
                         * 1、获取第一个html标签一直找结尾标签,如果在这个过程中遇到相同的标签收尾标签就要加1
                         * 2、第一个标签取到后继续第一步操作,找第2个元素 。。第N个元素
             */
            if (html == null) html = _html;
            var firstTag = Regex.Match(html, "<.+?>");

            List<string> eleList = new List<string>();
            List<HtmlInfo> reval = new List<HtmlInfo>();
            GetElementsStringList(html, ref eleList);
            foreach (var r in eleList)
            {
                HtmlInfo data = new HtmlInfo();
                data.OldFullHtml = r;
                data.SameLeveHtml = html;
                data.TagName = Regex.Match(r, @"(?<=\s{1}|\<)[a-z,A-Z]+(?=\>|\s)", RegexOptions.IgnoreCase).Value;
                data.InnerHtml = Regex.Match(r, @"(?<=\>).+(?=<)", RegexOptions.Singleline).Value;
                var eleBegin = Regex.Match(r, "<.+?>").Value;
                var attrList = Regex.Matches(eleBegin, @"[a-z,A-Z]+\="".+?""").Cast<Match>().Select(c => new { key = c.Value.Split(‘=‘).First(), value = c.Value.Split(‘=‘).Last().TrimEnd(‘"‘).TrimStart(‘"‘) }).ToList();
                data.Attributes = new Dictionary<string, string>();
                if (attrList != null && attrList.Count > 0)
                {
                    foreach (var a in attrList)
                    {
                        data.Attributes.Add(a.key, a.value);
                    }
                }
                reval.Add(data);
            }
            return reval;

        }

        #region private
        private List<HtmlInfo> GetDescendantsSource(List<HtmlInfo> allList, string elementName)
        {
            foreach (var r in allList)
            {
                if (r.InnerHtml == null || !r.InnerHtml.Contains("<")) continue;
                var childList = RootDescendants(r.InnerHtml).Where(c => elementName == null || c.TagName.ToLower() == elementName.ToLower()).ToList();
                if (childList == null || childList.Count == 0)
                {
                    childList = GetDescendantsSource(RootDescendants(r.InnerHtml), elementName);
                    if (childList != null && childList.Count > 0)
                        return childList;
                }
                else
                {
                    return childList;
                }
            }
            return null;
        }

        private void GetElementsStringList(string html, ref List<string> eleList)
        {
            HtmlInfo info = new HtmlInfo();
            info.TagName = Regex.Match(html, @"(?<=\<\s{0,5}|\<)([a-z,A-Z]+|h\d{1})(?=\>|\s)", RegexOptions.IgnoreCase).Value;
            string currentTagBeginReg = @"<\s{0,10}" + info.TagName + @".*?>";//获取当前标签元素开始标签正则
            string currentTagEndReg = @"\<\/" + info.TagName + @"\>";//获取当前标签元素收尾标签正则
            if (string.IsNullOrEmpty(info.TagName)) return;

            string eleHtml = "";
            //情况1 <a/>
            //情况2 <a></a>
            //情况3 <a> 错误格式
            //情况4endif
            if (Regex.IsMatch(html, @"<\s{0,10}" + info.TagName + "[^<].*?/>"))//单标签
            {
                eleHtml = Regex.Match(html, @"<\s{0,10}" + info.TagName + "[^<].*?/>").Value;
            }
            else if (!Regex.IsMatch(html, currentTagEndReg))//没有收尾
            {
                if (Regex.IsMatch(html, @"\s{0,10}\<\!\-\-\[if"))
                {
                    eleHtml = GetElementString(html, @"\s{0,10}\<\!\-\-\[if", @"\[endif\]\-\-\>", 1);
                }
                else
                {
                    eleHtml = Regex.Match(html, currentTagBeginReg,RegexOptions.Singleline).Value;
                }
            }
            else
            {
                eleHtml = GetElementString(html, currentTagBeginReg, currentTagEndReg, 1);
            }

            try
            {
                eleList.Add(eleHtml);
                html = html.Replace(eleHtml, "");
                html = Regex.Replace(html, @"<\!DOCTYPE.*?>", "");
                if (!Regex.IsMatch(html, @"^\s*$"))
                {
                    GetElementsStringList(html, ref eleList);
                }

            }
            catch (Exception ex)
            {
                throw new Exception("SORRY,您的HTML格式不能解析!!!");

            }

        }

        private string GetElementString(string html, string currentTagBeginReg, string currentTagEndReg, int i)
        {

            string newHtml = GetRegNextByNum(html, currentTagBeginReg, currentTagEndReg, i);
            var currentTagBeginMatches = Regex.Matches(newHtml, currentTagBeginReg, RegexOptions.Singleline).Cast<Match>().Select(c => c.Value).ToList();
            var currentTagEndMatches = Regex.Matches(newHtml, currentTagEndReg).Cast<Match>().Select(c => c.Value).ToList();
            if (currentTagBeginMatches.Count == currentTagEndMatches.Count)
            { //两个签标元素相等
                return newHtml;
            }
            return GetElementString(html, currentTagBeginReg, currentTagEndReg, ++i);
        }

        private string GetRegNextByNum(string val, string currentTagBeginReg, string currentTagEndReg, int i)
        {
            return Regex.Match(val, currentTagBeginReg + @"((.*?)" + currentTagEndReg + "){" + i + "}?", RegexOptions.IgnoreCase | RegexOptions.Singleline).Value;
        }
        #endregion

    }
    public static class XHtmlElementExtendsion
    {
        /// <summary>
        /// 获取最近的相同层级的HTML元素
        /// </summary>
        /// <param name="elementName">等于null为所有元素</param>
        /// <returns></returns>
        public static List<HtmlInfo> Descendants(this  IEnumerable<HtmlInfo> htmlInfoList, string elementName = null)
        {
            var html = htmlInfoList.First().InnerHtml;
            XHtmlElement xhe = new XHtmlElement(html);
            return xhe.Descendants(elementName);
        }
        /// <summary>
        /// 获取下级元素
        /// </summary>
        /// <param name="elementName"></param>
        /// <returns></returns>
        public static List<HtmlInfo> ChildDescendants(this  IEnumerable<HtmlInfo> htmlInfoList, string elementName = null)
        {
            var html = htmlInfoList.First().InnerHtml;
            XHtmlElement xhe = new XHtmlElement(html);
            return xhe.RootDescendants(html).Where(c => elementName == null || c.TagName == elementName).ToList();
        }

        /// <summary>
        /// 获取父级
        /// </summary>
        /// <param name="htmlInfoList"></param>
        /// <returns></returns>
        public static List<HtmlInfo> ParentDescendant(this  IEnumerable<HtmlInfo> htmlInfoList,string fullHtml)
        {
            var saveLeveHtml = htmlInfoList.First().SameLeveHtml;
            string replaceGuid=Guid.NewGuid().ToString();
            fullHtml = fullHtml.Replace(saveLeveHtml,replaceGuid);
            var parentHtml = Regex.Match(fullHtml, @"<[^<]+?>[^<]*?" + replaceGuid + @".*?<\/.+?>").Value;
            parentHtml = parentHtml.Replace(replaceGuid, saveLeveHtml);
            XHtmlElement xhe = new XHtmlElement(parentHtml);
            return xhe.RootDescendants();
        }
    }
    /// <summary>
    /// html信息类
    /// </summary>
    public class HtmlInfo
    {
        /// <summary>
        /// 元素名
        /// </summary>
        public string TagName { get; set; }
        /// <summary>
        /// 元素属性
        /// </summary>
        public Dictionary<string, string> Attributes { get; set; }
        /// <summary>
        /// 元素内部html
        /// </summary>
        public string InnerHtml { get; set; }

        public string OldFullHtml { get; set; }

        public string SameLeveHtml { get; set; }

        /// <summary>
        /// 得到元素的html
        /// </summary>
        /// <returns></returns>
        public string FullHtml
        {
            get
            {
                StringBuilder reval = new StringBuilder();
                string attributesString = string.Empty;
                if (Attributes != null && Attributes.Count > 0)
                {
                    attributesString = string.Join(" ", Attributes.Select(c => string.Format("{0}=\"{1}\"", c.Key, c.Value)));
                }
                reval.AppendFormat("<{0} {2}>{1}</{0}>", TagName, InnerHtml, attributesString);
                return reval.ToString();
            }
        }
    }
}

前台HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <a id="1">我是1</a>
    <a id="2" class="icon">icon</a>
    <img />
</body>
</html>
时间: 2024-11-12 05:09:32

HTML解析类 ,让你不使用正则也能轻松获取HTML相关元素 -C# .NET的相关文章

PHP模板解析类实例

作者:mckee 这篇文章主要介绍了PHP模板解析类,涉及php针对模板文件的解析与字符串处理的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下 1 <?php 2 class template { 3 private $vars = array(); 4 private $conf = ''; 5 private $tpl_name = 'index'; 6 //如果模板不存在 会查找当前 controller默认index模板 7 private $tpl_suffix = '.html

一个Ini文件解析类CIniFileParse

使用方法非常简单,看看源代码就明白了,该类支持Unicode文本. 一个Ini文件解析类CIniFileParse.rar

【转】C#类似Jquery的html解析类HtmlAgilityPack基础类介绍及运用

Html Agility Pack下载地址:http://htmlagilitypack.codeplex.com/ Html Agility Pack 源码中的类大概有28个左右,其实不算一个很复杂的类库,但它的功能确不弱,为解析DOM已经提供了足够强大的功能支持,可以跟jQuery操作DOM媲美:) 基础类和基础方法介绍 Html Agility Pack最常用的基础类其实不多,对解析DOM来说,就只有HtmlDocument和HtmlNode这两个常用的类,还有一个 HtmlNodeCol

IniParse解析类

说明 iniParse这个类是一个解析ini文件的类,他的功能和Windows下GetPrivateProfileString的功能一样,可以很方便的保存读取配置. 当然他不是只有GetPrivateProfileString这一个功能函数,它包含了整个Windows下的完整的功能集. iniParse有效的解决了使用Windows下的 API 频繁读取硬盘以及不能跨平台的问题,我本人在Mac和Windows下均编译成功,其功能也都测试成功. 网站 我的个人博客:http://www.solly

C#命令行参数解析类以及使用实例

http://blog.csdn.net/jackxinxu2100/article/details/6642694 编写命令行程序时如何进行命令行参数解析至关重要,下面将引用codeproject里面的一个命令行参数解析类并阐述如何使用来说明C#命令行参数解析的过程. 先看参数解析类,分为CommandLine类以及CommandArgs类,前者负责解析,后者负责结果封装,解析的结果分为三类:即 a=b 对应的key/value类型,-a b 对应的option与option value(可省

C++PE文件格式解析类(轻松制作自己的PE文件解析器)

PE是Portable Executable File Format(可移植的运行体)简写,它是眼下Windows平台上的主流可运行文件格式. PE文件里包括的内容非常多,详细我就不在这解释了,有兴趣的能够參看之后列出的參考资料及其它相关内容. 近期我也在学习PE文件格式,參考了很多资料.用C++封装了一个高效方便的PE文件格式解析的类. 该类对想学PE文件结构的朋友可算一份可贵的资料.代码均非常易懂,考虑较全面,具有一定的通用性. 同一时候该类也能够让想创建自己的PE文件解析软件的朋能够轻松在

黄聪:HtmlAgilityPack,C#实用的HTML解析类 ---- HtmlNode类

HtmlAgilityPack中的HtmlNode类与XmlNode类差不多,提供的功能也大同小异.下面来看看该类提供功能. 一.静态属性 public static Dictionary<string, HtmlElementFlag> //ElementsFlags;获取集合的定义为特定的元素节点的特定行为的标志.表包含小写标记名称作为键和作为值的 HtmlElementFlags 组合 DictionaryEntry 列表. public static readonly string H

转-Java基础深入解析——类与对象

转自CSDN博客,u010425776,http://m.blog.csdn.net/u010425776/article/details/46932867 成员变量与局部变量的区别 1.成员变量定义在类中,整个类中都能够访问.   局部变量定义在局部代码块中,只能在局部代码块中访问. 2.成员变量存在于堆内存中,有初始值. 局部变量存在于栈内存中,没有初始值. PS:成员变量分为静态成员变量和非静态成员变量,非静态成员变量存在堆内存中,静态成员变量存在静态方法区中. 静态方法区只存静态成员变量

VBA CSV格式的解析类 【c语言CSV Parser转换】

1 Option Explicit 2 '----------------读Csv文件 类--------------------- 3 4 Private Declare Function WideCharToMultiByte Lib "kernel32" _ 5 (ByVal CodePage As Long, _ 6 ByVal dwFlags As Long, _ 7 ByVal lpWideCharStr As Long, _ 8 ByVal cchWideChar As