0

0

XPath的not()函数怎么否定表达式?

幻夢星雲

幻夢星雲

发布时间:2025-08-16 16:55:01

|

628人浏览过

|

来源于php中文网

原创

not()函数用于反转XPath表达式的布尔结果,常用于筛选不满足特定条件的节点。其基本形式为not(expression),可否定属性存在、属性值、文本内容或子元素存在性。常见用法包括//div[not(@class)]选择无class属性的div,//a[not(@target='_blank')]排除target为_blank的链接。误区包括混淆not()作用范围,如not(//div[@class='active'])返回布尔值而非节点集,正确写法应为//div[not(@class='active')]。not()可与and、or结合使用,遵循德摩根定律,如//div[not(@id) and not(@class)]等价于//div[not(@id or @class)]。性能上,not()本身开销小,但内部复杂表达式可能影响效率,建议避免全局搜索,优先在谓词内使用以提高效率。

xpath的not()函数怎么否定表达式?

XPath的

not()
函数,说白了,就是用来否定一个表达式的结果。它会把一个原本为真的条件变成假,把假的变成真。你把它想象成一个“非”门,输入是真,输出就是假;输入是假,输出就是真。这在我们需要选择那些“不符合”某个条件的元素时,简直是神器。

解决方案

要否定一个XPath表达式,你只需要将该表达式作为

not()
函数的参数。它的基本形式是
not(expression)
。这个
expression
可以是任何能产生布尔值(真或假)的XPath表达式。

举几个例子,你就能立刻明白它的威力了:

not()
函数非常灵活,它可以嵌套在更复杂的表达式中,或者与其他逻辑运算符(如
and
or
)结合使用,来实现更精细的筛选。

XPath中not()函数的基本用法与常见误区是什么?

说实话,

not()
函数用起来简单,但要真正理解它的“哲学”,避免踩坑,还是得掰扯掰扯。

基本用法:

正如前面提到的,

not()
的核心就是“反转”逻辑。它最常见的应用场景就是作为谓词(
[]
)的一部分,用来过滤节点集。

常见误区:

这里有些坑,我个人就掉过好几次,后来才慢慢琢磨明白:

  1. 误区一:对空节点集的理解。 当一个XPath表达式的结果是空节点集时,在布尔上下文中它会被转换为

    false
    。非空节点集则转换为
    true

    • 比如
      //div[not(./span)]
      :如果当前
      div
      下有
      span
      ./span
      就是非空节点集,转换为
      true
      not(true)
      就是
      false
      ,这个
      div
      不被选中。如果当前
      div
      下没有
      span
      ./span
      就是空节点集,转换为
      false
      not(false)
      就是
      true
      ,这个
      div
      被选中。这符合预期。
    • 但如果你写
      not(//div[@class='active'])
      ,这通常不是你想要的效果。这个表达式会检查整个文档中是否存在任何一个
      class
      active
      div
      。如果存在,整个表达式就是
      false
      。如果一个都没有,整个表达式就是
      true
      。它返回的是一个单一的布尔值,而不是一个节点集。你大概率是想选择那些
      class
      不是
      active
      div
      ,那应该是
      //div[not(@class='active')]
  2. 误区二:

    not()
    的位置和
    作用域
    not()
    放在谓词内部,是针对当前节点进行判断;放在整个表达式外面,是针对整个表达式的结果进行判断。

    • //div[not(@class='active')]
      :选择所有
      class
      属性不等于
      active
      div
    • not(//div[@class='active'])
      :判断文档中是否存在
      class
      active
      div
      ,并返回其相反的布尔值。这是个全局性的判断。
  3. 误区三:与

    and
    /
    or
    的结合(德摩根定律)。
    有时候我们想否定一个复合条件,比如“既不是A也不是B”。

    • not(conditionA and conditionB)
      等价于
      not(conditionA) or not(conditionB)
    • not(conditionA or conditionB)
      等价于
      not(conditionA) and not(conditionB)
      。 理解这一点能帮助你写出更清晰、更符合逻辑的XPath。例如,你想找既没有
      id
      属性也没有
      class
      属性的
      div
      //div[not(@id) and not(@class)]
      或者等价的
      //div[not(@id or @class)]
      。我个人更倾向于前者,感觉逻辑更直观一些。

如何利用not()函数选择不包含特定属性或子元素的节点?

这几乎是

not()
函数最经典的用途了,也是日常工作中非常高频的场景。

Sesame AI
Sesame AI

一款开创性的语音AI伴侣,具备先进的自然对话能力和独特个性。

下载

选择不包含特定属性的节点:

  • 没有某个特定属性的节点: 如果你想找到页面上所有没有

    id
    属性的
    div
    元素,可以这样写:
    //div[not(@id)]
    这里的
    @id
    如果存在,就会被视为真,
    not()
    一否定就变假,该
    div
    不被选中。如果
    @id
    不存在,就是假,
    not()
    一否定就变真,该
    div
    就被选中。这非常简洁高效。

  • 某个属性的值不符合预期: 假设你有一堆链接,但你只想选择那些

    href
    属性不以
    #
    开头的(排除锚点链接):
    //a[not(starts-with(@href, '#'))]
    或者你想找所有
    img
    标签,但排除掉那些
    alt
    属性为空字符串的(通常意味着图片描述缺失):
    //img[not(@alt='')]

选择不包含特定子元素的节点:

  • 没有某个直接子元素的节点: 你可能想找到所有没有

    子元素的
    //div[not(./span)]
    这里的
    ./span
    表示查找当前
    div
    的直接子元素
    span
    。如果找到了,
    not()
    就让当前
    div
    不被选中;如果没找到,就选中它。

  • 没有某个特定类型的后代元素的节点: 如果你想找到所有

      列表,但排除掉那些内部任何地方(不一定是直接子元素)包含
      class
      selected
      • //ul[not(.//li[@class='selected'])]
        这里的
        .//li
        表示查找当前
        ul
        下的任意层级的
        li
        元素。

      • 不包含特定文本内容的节点: 比如你有一堆

        div
        ,你想找到那些内部文本不包含“广告”字样的
        div
        //div[not(contains(text(), '广告'))]
        或者更精确一点,不包含“免费”或“优惠”:
        //div[not(contains(text(), '免费') or contains(text(), '优惠'))]

      这些都是非常实用的场景,

      not()
      函数在这里发挥了它筛选“反向条件”的巨大作用。

      not()函数在复杂XPath表达式中的应用场景与性能考量

      在更复杂的XPath表达式里,

      not()
      函数就像一块乐高积木,可以灵活地嵌入,实现非常精细的筛选逻辑。但同时,我们也得稍微琢磨下它的性能,虽然在绝大多数Web抓取场景下,这点性能差异可能微不足道。

      复杂应用场景:

      1. 组合否定条件: 我们经常需要同时满足多个否定条件。比如,我想找一个

        div
        ,它既没有
        id
        属性,
        class
        也不是
        hidden
        //div[not(@id) and not(@class='hidden')]
        或者,你也可以利用德摩根定律,写成:
        //div[not(@id or @class='hidden')]
        这两种写法在逻辑上是等价的,具体用哪个,看你个人觉得哪个更清晰。我个人偏好第一个,感觉更直观。

      2. 否定函数结果:

        not()
        可以否定其他函数的返回结果。

        • 找那些文本内容不为空
          p
          标签:
          //p[not(normalize-space(text()) = '')]
          这里
          normalize-space()
          会移除文本前后的空白字符,并将内部连续空白替换为单个空格。
          not()
          再判断结果是否为空。
        • 找那些子元素数量不等于5的
          ul
          //ul[not(count(./li) = 5)]
          这等价于
          //ul[count(./li) != 5]
          ,但用
          not()
          有时候能让逻辑更统一。
      3. 结合位置谓词: 比如,选择一个

        ul
        中,除了第一个
        li
        之外的所有
        li
        //ul/li[not(position() = 1)]
        这等价于
        //ul/li[position() > 1]
        //ul/li[not(self::li[1])]

      性能考量:

      说实话,谈性能在XPath层面,很多时候有点“玄学”,因为实际的解析器实现、文档大小、以及你所使用的库或工具的优化程度都会有影响。但总的原则是,让你的表达式越具体越好,减少引擎的遍历范围。

      • not()
        本身通常不会成为性能瓶颈。
        它只是一个逻辑操作符。真正的性能开销通常来自于它内部的表达式,尤其是当这个表达式需要遍历大量节点或者执行复杂计算时。
      • 避免不必要的全局搜索: 如果你写
        not(//div[@class='active'])
        ,XPath引擎可能需要遍历整个文档来确定是否存在这样的
        div
        。如果你的目标是过滤一个已知的节点集,把
        not()
        放在谓词里通常更高效。 例如,你已经定位到了一组
        div
        ,现在想从这组
        div
        中筛选出没有特定属性的,那么
        //div[not(@attribute)]
        肯定比先获取所有
        div
        再在外部做
        not()
        判断要好。
      • 复杂表达式的优化:
        not()
        内部的表达式非常复杂时,性能可能会受影响。比如
        not(contains(concat(@id, @name, text()), 'keyword'))
        这种,因为它需要拼接字符串再进行搜索。 在某些极端情况下,如果性能真的成了问题,你可能需要考虑是否能用其他XPath函数或者在代码层面(比如Python的BeautifulSoup或lxml)进行后处理来达到同样的效果。但对于大多数Web抓取任务来说,不必过度担心
        not()
        的性能,它的简洁和表达力带来的效率提升往往远超那点微小的计算开销。

      最终,掌握

      not()
      的关键在于理解它如何将“真”变为“假”,以及它在不同上下文(特别是谓词中)的作用。多写多练,自然就熟了。

      热门AI工具

      更多
      DeepSeek
      DeepSeek

      幻方量化公司旗下的开源大模型平台

      豆包大模型
      豆包大模型

      字节跳动自主研发的一系列大型语言模型

      通义千问
      通义千问

      阿里巴巴推出的全能AI助手

      腾讯元宝
      腾讯元宝

      腾讯混元平台推出的AI助手

      文心一言
      文心一言

      文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

      讯飞写作
      讯飞写作

      基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

      即梦AI
      即梦AI

      一站式AI创作平台,免费AI图片和视频生成。

      ChatGPT
      ChatGPT

      最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

      相关专题

      更多
      Python爬虫获取数据的方法
      Python爬虫获取数据的方法

      Python爬虫可以通过请求库发送HTTP请求、解析库解析HTML、正则表达式提取数据,或使用数据抓取框架来获取数据。更多关于Python爬虫相关知识。详情阅读本专题下面的文章。php中文网欢迎大家前来学习。

      293

      2023.11.13

      java基础知识汇总
      java基础知识汇总

      java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

      1503

      2023.10.24

      Go语言中的运算符有哪些
      Go语言中的运算符有哪些

      Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

      233

      2024.02.23

      php三元运算符用法
      php三元运算符用法

      本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

      87

      2025.10.17

      counta和count的区别
      counta和count的区别

      Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

      198

      2023.11.20

      js 字符串转数组
      js 字符串转数组

      js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

      340

      2023.08.03

      js截取字符串的方法
      js截取字符串的方法

      js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

      212

      2023.09.04

      java基础知识汇总
      java基础知识汇总

      java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

      1503

      2023.10.24

      2026赚钱平台入口大全
      2026赚钱平台入口大全

      2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

      54

      2026.01.31

      热门下载

      更多
      网站特效
      /
      网站源码
      /
      网站素材
      /
      前端模板

      精品课程

      更多
      相关推荐
      /
      热门推荐
      /
      最新课程
      最新Python教程 从入门到精通
      最新Python教程 从入门到精通

      共4课时 | 22.4万人学习

      Django 教程
      Django 教程

      共28课时 | 3.7万人学习

      SciPy 教程
      SciPy 教程

      共10课时 | 1.3万人学习

      关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
      php中文网:公益在线php培训,帮助PHP学习者快速成长!
      关注服务号 技术交流群
      PHP中文网订阅号
      每天精选资源文章推送

      Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号