使用xpath实现document.querySelector样式选择器进行html解析(二):扩展一下xpath以便支持正则

本文主要是介绍使用xpath实现document.querySelector样式选择器进行html解析(二):扩展一下xpath以便支持正则,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

使用xpath实现document.querySelector样式选择器进行html解析(一):将html转成xml

使用xpath实现document.querySelector样式选择器进行html解析(二):扩展一下xpath以便支持正则

使用xpath实现document.querySelector样式选择器进行html解析(三):实现样式选择器

使用xpath实现document.querySelector样式选择器进行html解析(四):将选择结果封装进行输出

-----------------------------------------------------------------

继续我们的工作,在进行下一步之前,先考虑一下,为了支持css选择器,我们需要使用xpath完成哪些东西

标签选择器。。。。这个很简单嘛,//*[name()='tagName'],完全就是标签选择器嘛,根本都不需要再加工了

id选择器。。。。这个好像也很容易,//*[@id='ID'],貌似也挺容易

再看看类选择器。。。。好像有点问题,//*[contains(@class,'className')] 到是能把符合条件的节点选择出来,但是结果貌似比我们预期的要多了?他连 class="classNameA"、class="PickclassName"之类的也给匹配上了?!

Hmmmmmmmmmmm,好吧,在类选择器上,看来是必须扩展一下xpath的方法了,不管是扩展一个正则支持,还是扩展一个其他自定义函数支持,就看个人爱好了,文盲个人是倾向用正则来搞一下,毕竟除了以上三个基本选择器,后边还有属性选择器等着我们实现类似*=啦、^=啦、$=啦,嗯。。。。。为了再htmlParser中不使用正则,结果编写的实现代码中,正则还是不少啊。。。

好了,我们开始去实现一下xpath的扩展吧,这个东西网上搜一搜还是挺多了,基本上就是XsltContext、IXsltContextFunction来对xpath进行扩展

    public class XpathContext: XsltContext{private XsltArgumentList _args;public XpathContext(){}public XpathContext(NameTable nt) : base(nt){}public XpathContext(NameTable nt,XsltArgumentList args) : base(nt){_args = args;}public XsltArgumentList ArgList{get{return _args;}}public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] ArgTypes){XPathExtensionFunction fun = null;switch (prefix){case "regex":    // 这里是前缀名switch (name){case "ismatch":    // 这里是函数名,下边的委托中,第一个参数是委托调用的函数名?应该可以这么说吧。。。。fun = new XPathExtensionFunction("RegexIsMatch", 1, 2, new XPathResultType[] { XPathResultType.NodeSet, XPathResultType.String }, XPathResultType.Boolean);break;}break;}return fun;}public override IXsltContextVariable ResolveVariable(string prefix, string name){XPathExtensionVariable result = new XPathExtensionVariable(name);return result;}public override int CompareDocument(string baseUri, string nextbaseUri){return 0;}public override bool PreserveWhitespace(XPathNavigator node){return true;}public override bool Whitespace{get{return true;}}}public class XPathExtensionFunction : IXsltContextFunction{private XPathResultType[] _xprts;private XPathResultType _xprt;private string _fn;private int _min;private int _max;public int Minargs{get{return _min;}}public int Maxargs{get{return _max;}}public XPathResultType[] ArgTypes{get{return _xprts;}}public XPathResultType ReturnType{get{return _xprt;}}public XPathExtensionFunction(string fn, int min, int max, XPathResultType[] argTypes, XPathResultType returnType){_fn = fn;_min = min;_max = max;_xprts = argTypes;_xprt = returnType;}public object Invoke(XsltContext xls,object[] args,XPathNavigator doc){switch (_fn)    // 根据函数名,进行具体实现。Hmmmmmmm,应该可以叫做函数名吧。^v^{case "RegexIsMatch": // 具体实现稍后再说return false;}return null;}}public class XPathExtensionVariable : IXsltContextVariable{private string _fn = string.Empty;public XPathExtensionVariable(string fn){_fn = fn;}public object Evaluate(XsltContext xsl){XsltArgumentList vars = ((XpathContext)xsl).ArgList;return vars.GetParam(_fn, null);}public bool IsLocal{get{return false;}}public bool IsParam{get{return false;}}public XPathResultType VariableType{get{return XPathResultType.Any;}}}

呵呵,别看上边这些代码一大片,其实。。。。都是网上抄的,嗯,真的,文盲同学抄完了之后,都没弄明白各个方法之间传递的都是什么玩意,结果一不小心掉到坑里了,先不要关正则的实现,看看我们的类选择器应该怎么实现

前边已经说了,//*[contains(@class,'className')]不合适,那么用正则来进行选择就好了,//*[regex:ismatch(@class,'(?<!\w)className(?!\w)')],嗯,这个正则很标准嘛,肯定不会选择出多余的东西。。。。好吧,我说的早了,被打脸了

问题出在什么地方?仔细调试后发现在具体实现的地方,也就是Invoke方法里,我所设置的@class传递进来的是个什么玩意?怎么看都没有发现和class这个属性有关系。。。。

然后再想想,正则除了需要和属性计算之外,还可以和节点的正文计算,或者下一级指定节点的正文进行计算,嗯。。。xpath有这个功能,比如//div[.='标题']、//div[a=链接],好吧,我们先吧选择器调整调整//*[regex:ismatch('@class','(?<!\w)className(?!\w)')],嗯,这次Invoke传递进来的参数args的所有元素我都可以看懂了,进来了两个字符串,嘿嘿

具体实现正则其实就很简单了。。。

        public object Invoke(XsltContext xls,object[] args,XPathNavigator doc){XmlElement xe = doc.UnderlyingObject as XmlElement;switch (_fn){case "RegexIsMatch":string att = args[0].ToString();string reg = args[1].ToString();// 按属性匹配if (att.Substring(0, 1) == "@"){if (xe.Attributes.GetNamedItem(att.Substring(1)) == null){return false;}else{// 考虑到css选择器是区分大小写的,所以这里的正则就不忽视大小写了return Regex.IsMatch(xe.Attributes.GetNamedItem(att.Substring(1)).Value, reg);}}// 实现其他正则需要实现的匹配return false;}return null;}

哦了,关于xpath的扩展我们也就写好了,使用这个扩展的方式也很简单,直接 xml.SelectNodes("//div",new XpathContext())即可,嗯,我是将这个扔到一个静态类里,这样只需要实例化一次就可以了

补充两个方法,XmlExpand的

        public static XmlNode addNode(XmlNode node, string name, string namespaceURI){if (node == null){return null;}XmlNode n = node.OwnerDocument.CreateNode(XmlNodeType.Element, name, namespaceURI);node.AppendChild(n);return n;}public static XmlNode addNode(XmlNode node, string name){return addNode(node, name, "");}
        public static void setAttribute(XmlNode node, string name, string attrib, string namespaceURI){if (node.Name == "#text"){return;}if (node.Attributes[name] != null){node.Attributes.GetNamedItem(name).Value = attrib;}else{XmlNode att = node.OwnerDocument.CreateNode(XmlNodeType.Attribute, name, namespaceURI);att.Value = attrib;node.Attributes.SetNamedItem(att);}}public static void setAttribute(XmlNode node, string name, string attrib){setAttribute(node,name,attrib,"");}

这篇关于使用xpath实现document.querySelector样式选择器进行html解析(二):扩展一下xpath以便支持正则的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/746662

相关文章

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

pytorch自动求梯度autograd的实现

《pytorch自动求梯度autograd的实现》autograd是一个自动微分引擎,它可以自动计算张量的梯度,本文主要介绍了pytorch自动求梯度autograd的实现,具有一定的参考价值,感兴趣... autograd是pytorch构建神经网络的核心。在 PyTorch 中,结合以下代码例子,当你

C#中async await异步关键字用法和异步的底层原理全解析

《C#中asyncawait异步关键字用法和异步的底层原理全解析》:本文主要介绍C#中asyncawait异步关键字用法和异步的底层原理全解析,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录C#异步编程一、异步编程基础二、异步方法的工作原理三、代码示例四、编译后的底层实现五、总结C#异步编程

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

前端CSS Grid 布局示例详解

《前端CSSGrid布局示例详解》CSSGrid是一种二维布局系统,可以同时控制行和列,相比Flex(一维布局),更适合用在整体页面布局或复杂模块结构中,:本文主要介绍前端CSSGri... 目录css Grid 布局详解(通俗易懂版)一、概述二、基础概念三、创建 Grid 容器四、定义网格行和列五、设置行

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3