赞
踩
使用xpath实现document.querySelector样式选择器进行html解析(三):实现样式选择器
使用xpath实现document.querySelector样式选择器进行html解析(四):将选择结果封装进行输出
-----------------------------------------------------------------
恩,其实到目前为止,关于xpath解析html的样式选择器其实已经完工了,而且,应该说比预期的目的还多出了一丢丢的效果
例如:QuerySelector("*[style*='(?<!\w)font-weight\s*:\s*bold(?!\w)']"),可以选中所有style属性中包含粗体定义的节点
例如:QuerySelector("*:contains(abc.*?xyz)"),可以选中所有正文中包含abc和xyz,且abc在xyz之前的节点
注意到没有,我们可以直接使用正则,当然了,第三章我贴的伪类contains处理之前的那个正则不支持圆括号输入,关于指定属性的正则不支持方括号输入,自己魔改一下就可以完整的支持正则了,或者比较麻烦,需要层深计算,但还是可以实现的,可以参考文盲老顾之前关于正则的博文,但是个人感觉没什么必要了
本章为选择器的最后一章,关于结果输出方式的,有自己代码风格的可以不看,毕竟文盲老顾也是半路出家的c#工作者,没有考虑到的,没有学习到的东西都还很多,有更好的结果输出方案的也请告知文盲,让文盲继续进步哦
-----------------------------------------------------------------
- public HtmlObjectResult QuerySelector(string selection)
- {
- string xpath = CssParser.ParseCSS(selection);
- try
- {
- return new HtmlObjectResult(_xml.SelectNodes(xpath, XMLExpand.XPathExpand));
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
直接将返回的XmlNodeList封装到一个类里,作为结果实现
- public class HtmlObjectResult
- {
- private List<HtmlObjectNode> _result = new List<HtmlObjectNode>();
- private int _curr = 0;
- public int Count
- {
- get
- {
- return _result == null ? 0 : _result.Count;
- }
- }
- public HtmlObjectNode[] NodeCollection
- {
- get
- {
- return _result.ToArray();
- }
- }
- public HtmlObjectNode Node
- {
- get
- {
- return _result == null ? null : _result[_curr];
- }
- }
- public HtmlObjectResult(XmlNodeList xnl)
- {
- for (int i = 0; i < xnl.Count; i++)
- {
- _result.Add(new HtmlObjectNode(xnl[i]));
- }
- }
- public HtmlObjectResult Next
- {
- get
- {
- _curr += _curr < _result.Count - 1 ? 1 : 0;
- return this;
- }
- }
- public HtmlObjectResult Previous
- {
- get
- {
- _curr -= _curr > 0 ? 1 : 0;
- return this;
- }
- }
- public HtmlObjectResult First
- {
- get
- {
- _curr = 0;
- return this;
- }
- }
- }
对于结果来说,它其实是一个节点集合,所以,提供一个Count,来表示到底有多少节点被选中
一般情况下,我们都是直接使用的第一个节点作为我们的结果,所以定义一个First,如果需要其他结果,可以用Next、Previous来选择不同的结果,恩,反正都是返回这个结果集本身,只是下标定位改变了而已
然后可以返回当前选中的结果作为输出内容,也就是Node属性,Node也是一个封装后的xml节点,稍后再讲
当然,如果不喜欢这些,可以直接输出所有的结果,NodeCollection可以满足你的需要,当然其中的元素也是被封装好的结果节点
再然后是正式输出我们期望的结果值了
- public class HtmlObjectNode
- {
- private XmlNode _node = null;
- public HtmlObjectNode(XmlNode node)
- {
- _node = node;
- }
- public HtmlObjectNode Next
- {
- get
- {
- return _node == null ? null : _node.NextSibling != null ? new HtmlObjectNode(_node.NextSibling) : this;
- }
- }
- public HtmlObjectNode Previous
- {
- get
- {
- return _node == null ? null : _node.PreviousSibling != null ? new HtmlObjectNode(_node.PreviousSibling) : this;
- }
- }
- public HtmlObjectNode Parent
- {
- get
- {
- return _node == null ? null : _node.ParentNode != null ? new HtmlObjectNode(_node.ParentNode) : this;
- }
- }
- public string InnerHtml
- {
- get
- {
- return _node == null ? null : Regex.Replace(_node.InnerXml, @"<!\[CDATA\[|\]\]>", "", RegexOptions.IgnoreCase).Trim();
- }
- }
- public string OuterHtml
- {
- get
- {
- return _node == null ? null : Regex.Replace(_node.OuterXml, @"<!\[CDATA\[|\]\]>", "", RegexOptions.IgnoreCase).Trim();
- }
- }
- public string InnerText
- {
- get
- {
- return _node == null ? null : _node.InnerText;
- }
- }
- public XmlNode Node
- {
- get
- {
- return _node;
- }
- }
- }
作为被选中的节点,有时候我们需要纯文本内容,有时候需要html内容,html内容有时候需要包含节点本身,有时候不包含
所以,我们的结果输出就直接定义成三个,分别是InnerText、InnerHtml、OuterHtml,这个也符合html本身的习惯
由于我在第一章的时候,将html转成xml的时候还追加了不少的CDataSetion节点,这些节点在作为结果输出的时候应该被删除节点声明,所以我在这里用正则删除了一些信息
当然,有时候某些节点定位非常麻烦,可他相邻的部分节点非常好定位,那么我们通常会定位到我们希望选中的节点之前,例如有一个表格,很多行很多列,没有样式啦、ID啦,甚至数据的位置也可能改变,但表格的格式不变,比如每一个td声明数据名称后,下一个紧跟着的td必定是它对应的值的时候,我们就可以直接定位到这个数据名称的位置,例如 QuerySelector("td:contains(姓名)"),然后使用Next向后移动一个节点,再输出就是对应的值了:QuerySelector("td:contains(姓名)").First.Node.Next.InnerText
需要注意的是,Node之前的Next是在结果集中选择下一个对应的结果,Node之后的Next是在Html中对应的元素的下一个元素
好了,HtmlParser部分基本上讲完了,之后文盲老顾会尝试做一些数据提取方面新的尝试,在尽量减少指正的情况下,如何从页面内获取到我们想要的数据,例如自动解析表格之类的
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。