XPath的comment()函数是专门用于匹配文档中注释节点的内置函数,注释节点指的是文档中以<!--开头、以-->结尾的内容片段,在处理包含注释的XML或HTML文档时,comment()能快速定位到这些特殊节点。
comment()基本语法
comment()不需要传入任何参数,直接作为XPath表达式的节点测试部分使用,基本语法格式如下:
<!-- 基础语法:选择当前上下文下的所有注释节点 --> comment() <!-- 选择根节点下的所有注释节点 --> /comment() <!-- 选择指定元素下的所有注释节点 --> //book/comment()
XML文档中使用comment()选择注释节点
假设我们有如下的XML文档,其中包含多个注释节点:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<!-- 这里是书店的根注释 -->
<book category="编程">
<!-- 这是编程类书籍的注释 -->
<title>XPath实战指南</title>
<author>张三</author>
</book>
<book category="文学">
<title>散文精选</title>
<!-- 文学类书籍暂无作者信息 -->
</book>
</bookstore>
我们可以通过不同的XPath表达式选择对应的注释节点:
- 表达式
/bookstore/comment()会选择到内容为"这里是书店的根注释"的注释节点 - 表达式
//book/comment()会选择到两个book元素下的所有注释节点,即"这是编程类书籍的注释"和"文学类书籍暂无作者信息" - 表达式
//comment()会选择文档中所有的注释节点,共3个
HTML文档中使用comment()选择注释节点
在处理HTML文档时,comment()同样适用,比如我们有如下HTML片段:
<!DOCTYPE html>
<html>
<head>
<!-- 页面元信息注释 -->
<meta charset="UTF-8">
</head>
<body>
<div class="content">
<!-- 内容区域开始 -->
<p>这是正文内容</p>
</div>
</body>
</html>
对应的XPath选择逻辑如下:
# 使用lxml库解析HTML并选择注释节点的示例
from lxml import etree
html_str = """<!DOCTYPE html>
<html>
<head>
<!-- 页面元信息注释 -->
<meta charset="UTF-8">
</head>
<body>
<div class="content">
<!-- 内容区域开始 -->
<p>这是正文内容</p>
</div>
</body>
</html>"""
# 解析HTML
html_obj = etree.HTML(html_str)
# 选择所有注释节点
comments = html_obj.xpath("//comment()")
for comment in comments:
print(comment.text)
# 输出结果:
# 页面元信息注释
# 内容区域开始
使用comment()的注意事项
- comment()只能匹配注释节点,不能匹配其他类型的节点,比如元素节点、文本节点等,如果需要同时选择多种节点,可以结合
|运算符使用,例如//comment() | //title可以同时选择所有注释节点和title元素节点 - 注释节点的文本内容不包含<!--和-->这两个边界符号,通过comment()获取到的节点文本就是注释内部的纯内容
- 如果文档中没有注释节点,使用comment()的表达式会返回空的节点集合,不会抛出异常,实际使用时可以先判断返回结果的长度
- 在XPath 1.0版本中,comment()是标准支持的函数,主流的XPath解析库如lxml、xpath.js等都支持该函数的使用
常见使用场景
comment()在实际开发中有很多实用场景,比如:
- 爬取网页时,有些网页会把反爬的提示信息放在注释中,通过comment()可以快速提取这些隐藏信息
- 处理遗留的XML配置文件时,需要提取注释中的版本说明、修改记录等信息
- 文档清洗时,需要批量删除或替换注释节点,可以先通过comment()定位到所有注释再进行处理