except运算符用于求两个节点集的差集,返回第一个节点集中不在第二个节点集中的节点,语法为“节点集A except 节点集B”,适用于XPath 2.0及以上版本;在XPath 1.0中可通过[not()]谓词实现类似效果,如//p[not(@id='p2')];与union(并集)和intersect(交集)共同构成XPath集合操作体系,广泛应用于网页抓取中的内容清洗与干扰元素排除。

XPath中的
except
当我第一次接触到
except
except
它的基本语法是:
节点集A except 节点集B
节点集A
节点集B
举个例子,假设我们有这样的HTML结构:
<div> <p id="p1">这是一个段落。</p> <span id="s1">这是一个span。</span> <p id="p2">这是另一个段落。</p> <a id="a1" href="internal.html">内部链接</a> <a id="a2" href="external.com">外部链接</a> </div>
如果我们想选择所有
p
id
p2
//p except //p[@id='p2']
<p id="p1">这是一个段落。</p>
再来一个更复杂的场景,比如我们想获取所有的
div
class="header"
div
<body>
<div class="main">
<div class="header">Header 1</div>
<div>Content 1</div>
<div class="header">Header 2</div>
<div>Content 2</div>
</div>
</body>XPath可以写成:
//div[@class='main']/* except //div[@class='header']
//div[@class='main']/*
main
div
except //div[@class='header']
header
div
<div>Content 1</div>
<div>Content 2</div>
有一点需要注意,
except
[not()]
这确实是个现实问题。我之前就遇到过,在一些遗留系统里,虽然XPath 2.0已经普及很久了,但它们的底层解析器依然停留在1.0版本。这时候
except
最常见的替代方案是利用谓词(predicates)中的
not()
节点集A[not(条件B)]
举个例子,还是刚才那个需求:选择所有
p
id
p2
//p[not(@id='p2')]
p
id
p2
//p except //p[@id='p2']
再看那个剔除
header
div
<body>
<div class="main">
<div class="header">Header 1</div>
<div>Content 1</div>
<div class="header">Header 2</div>
<div>Content 2</div>
</div>
</body>XPath 1.0的写法可以是:
//div[@class='main']/*[not(@class='header')]
class
main
div
[not(@class='header')]
class
header
这种方式虽然不如
except
not()
not()
except
except
union
intersect
当我们谈论
except
union
intersect
union
节点集A | 节点集B
节点集A
节点集B
h1
h2
//h1 | //h2
union
intersect
节点集A intersect 节点集B
class="active"
class="selected"
div
class="active"
div
class="selected"
div
intersect
intersect
except
union
而
except
这三个操作符,
union
intersect
except
except
理论知识学得再好,最终还是要落到实际应用上。
except
一个非常典型的场景是内容清洗。 想象一下,你正在抓取一个新闻网站的文章内容。通常,文章主体会被放在一个特定的
div
article
假设文章内容在
<div id="article-body">
<div class="ad-block">
<figcaption>
//div[@id='article-body']//text()
except
//div[@id='article-body']//*[not(self::script or self::style)] except //div[@class='ad-block'] except //figcaption
article-body
//*[not(self::script or self::style)]
ad-block
div
figcaption
另一个例子是导航菜单的排除。 你可能想抓取页面上所有的链接,但是导航菜单里的链接往往是重复的或者功能性的,你只想要正文或者侧边栏里的链接。 假设导航菜单在
<nav>
//a except //nav//a
<a>
<nav>
<a>
有时候,网站会有一些通用的模板元素,比如页脚(footer)或者侧边栏(sidebar),它们包含一些你不想重复抓取的信息。如果这些元素有明确的标识(ID或Class),你就可以用
except
div
//div except //footer//div except //aside//div
这些应用场景都体现了
except
以上就是XPath的except运算符如何求差集?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号