zoukankan      html  css  js  c++  java
  • 实现html转Xml

    最近在做一些网页信息采集的工作,说通俗点就是爬虫工具,要监控页面中某一部分内容是否发生变化。起初考虑用正则表达式去匹配网页源码,经过咨询有经验人士,推荐使用xpath去获取页面内容能获得更好的效率。但是对于html这种宽松语法要求的语言来说,不可能100%地完全符合xml标准,那么就没法使用xpath,说得更直接点就是:不能把html源码直接加载到xmldocument中。为了使用xpath,只能对html内容进行转换或者规范,于是就写了这么一个方法。

    该方法比较地偷懒,借助了开源工具htmlparser获取html源码中的所有节点,然后遍历各个节点,转换为对应的xmlnode。对于html中有未闭合的节点,在转换后实际代码会有一些差别,但是不影响xpath的使用(这也跟如何写xpath的内容有关)。

    实现方式如下,需引用htmlparser的dll


        /// <summary>
        /// 解析Xml文件的帮助类
        /// </summary>
        public class XMLHelper
        {
            /// <summary>
            /// 有效名称的正则表达式
            /// </summary>
            static string validName = @"^[^$/;""!#).]+$";

            #region CovertHtmlToXml
            /// <summary>
            /// 转换html源码为xml格式
            /// </summary>
            /// <param name="html">html源码</param>
            /// <returns>xml字符串</returns>
            /// <param name="TargetTag">需转换的标记名</param>
            public static string CovertHtmlToXml(string html, string targetTag)
            {
                try
                {
                    XmlDocument doc = new XmlDocument();
                    XmlNode xmlDeclaration = doc.CreateXmlDeclaration("1.0", "utf-8", null);
                    doc.AppendChild(xmlDeclaration);

                    // 借助htmlparser解析html内容
                    Parser parser = Parser.CreateParser(html, "GBK");
                    // 筛选出指定的节点
                    TagNameFilter tnf = new TagNameFilter(targetTag);
                    NodeList nodes = parser.Parse(tnf);

                    // 创建根节点
                    XmlElement root = doc.CreateElement("Tags");

                    TagNode tagNode = null;
                    Hashtable ht = null;
                    XmlAttribute attr = null;
                    XmlElement parent = null;
                    for (int i = 0; i < nodes.Size(); i++)
                    {
                        tagNode = nodes[i] as TagNode;
                        parent = doc.CreateElement(tagNode.TagName);
                        
                        // 添加属性
                        ht = tagNode.Attributes;
                        foreach (DictionaryEntry ent in ht)
                        {
                            // 查看属性名是否合法
                            if (Regex.IsMatch(ent.Key.ToString(), validName))
                            {
                                attr = doc.CreateAttribute(ent.Key.ToString());
                                attr.Value = ent.Value.ToString();
                                parent.Attributes.Append(attr);
                            }
                        }// end foreach (DictionaryEntry ent in ht)

                        AppendChild(tagNode, parent, doc);

                        root.AppendChild(parent);
                    }
                    doc.AppendChild(root);

                    return doc.OuterXml;

                    //throw new Exception("给定的html文本必须至少包含一个" + targetTag + "节点");
                }
                catch (Exception ex)
                {
                    throw new Exception("转换html内容出错:" + ex.Message);
                }
            }

            /// <summary>
            /// 添加子节点
            /// </summary>
            /// <param name="tagNode">Html的父节点</param>
            /// <param name="parent">Xml的父节点</param>
            /// <param name="doc">Xml文档对象</param>
            private static void AppendChild(INode tagNode, XmlNode parent, XmlDocument doc)
            {
                INode node = null;
                XmlNode xmlNode = null;
                XmlAttribute attr = null;
                Hashtable ht = null;

                // 判断是否包含子节点
                if (tagNode.Children != null && tagNode.Children.Size() > 0)
                {
                    for (int i = 0; i < tagNode.Children.Size(); i++)
                    {
                        node = tagNode.Children[i];
                        xmlNode = null;
                        attr = null;
                        ht = null;

                        // 如果是html标记节点
                        if (node is TagNode)
                        {
                            TagNode tn = node as TagNode;
                            if (Regex.IsMatch(tn.TagName, validName))
                            {
                                xmlNode = doc.CreateElement(tn.TagName);

                                // 添加属性
                                ht = tn.Attributes;
                                foreach (DictionaryEntry ent in ht)
                                {
                                    // 查看属性名是否合法
                                    if (Regex.IsMatch(ent.Key.ToString(), validName))
                                    {
                                        attr = doc.CreateAttribute(ent.Key.ToString());
                                        attr.Value = ent.Value.ToString();
                                        xmlNode.Attributes.Append(attr);
                                    }
                                }
                            }
                        }

                        // 如果是文本节点
                        if (node is TextNode)
                        {
                            xmlNode = doc.CreateTextNode((node as TextNode).ToPlainTextString());
                        }

                        if (xmlNode != null)
                        {
                            parent.AppendChild(xmlNode);
                            AppendChild(node, xmlNode, doc);
                        }
                    }
                }
            }
            #endregion
        }
  • 相关阅读:
    Atitit sumdoc t5 final file list \sumdoc t5 final\sumdoc t511 \sumdoc t5 final\sumdoc t511.zip \sum
    上课流程法如何上好第一节课(1) 目录 1. 目录 1 1.1. 销售自己 1 1.2. 销售课程 1 1.3. 学习方法 1 1.4. 制定规章 2 2. 销售自己自我介绍 2 2.1.
    Atitit 重复文件清理工具 按照文件名 目录 1. 原理, 1 1.1. If base filex exist dele other files 1 1.2. Get getStartIdex
    Atitit sumdoc index 2019 v6 t56 .docx Atitit sumdoc index s99 目录 1. Zip ver 1 1.1. C:\Users\Adminis
    Atitit lucence es solr的各种query 与sql运算符的对比 目录 1.1. 等于运算 TermQuery 1 1.2. 范围运算 1 1.3. 大小运算 1 1.4. Wi
    Atitit 程序设计概论 艾提拉著作 目录 1. 界面ui设计 1 2. 编程语言部分 1 3. 面向对象的程序设计 1 4. 算法章节 数据结构 1 5. 第21章 标准库 2 5.1. 文件i
    Atitit 命令行执行sql 跨语言 目录 1.1. 无需输入密码,那就不要p参数即可 1 1.2. 4.使用mysql命令执行 1 1.3. 5.mysql命令执行sql,并将查询结果保存到
    Atitit java播放 wav MIXER 混响器编程 目录 1.1. MIXER 混响器编程 1 1.2. 得到系统中一共有多少个混音器设备: 1 1.3. 接口摘要 1 1.4. 调节音量
    Atitit object 和class的理解 目录 1.1. 发现很多Object的方法都是相同的,他们被重复地放在一个个对象当中,太浪费了。 1 1.2. 那我们怎么把这些Object给创建起来
    Atitit 数据库的历史与未来 目录 1.1. 两个对于数据库强需求的行业。电信 金融 1 1.2. 艾提拉分析 对数据库强需求行业金融 1 2. 数据库历史 2 2.1. ,上个世纪50,6
  • 原文地址:https://www.cnblogs.com/dekevin/p/4042451.html
Copyright © 2011-2022 走看看