piapia123
zh

XPath 与 JSONPath 测试

文本

所有处理都在浏览器本地完成,数据不上传服务器

输入
把文件拖到这里可直接载入
输出

把内容粘进来,写一条路径,看它选中了什么。常见的几种用法:`//a/@href` 抓全部链接、`//img/@src` 抓全部图片地址、`//h2` 取出所有小标题,或者 `$.store.book[*].title` 从接口返回里取出全部书名、`$..id` 找出所有层级的 id。 为什么两套语法共用一个页面:它们的形状完全一样 —— 一条路径 + 一份文档 → 一组结果。分开做的话,你得先判断「我手里这份是 JSON 还是 XML」再去挑工具,而那个判断在你把内容粘进来之前是多余的。上面选一下语法就行。 两套都是明确的子集。 支持的写法写在下面;不支持的写法会明确报「不支持」,而不是给出一个空结果 —— 因为「语法没被实现」与「真的没匹配到」在屏幕上一模一样,前者会让你以为自己的选择器写错了。 JSONPath 没有事实标准,这一条要提前知道:`$..book[?(@.price<10)]` 在 JavaScript、Python、Java 的各个 JSONPath 库里结果并不一致(切片边界、递归下降是否包含自身,各家做法不同)。RFC 9535 到 2024 年才定下来。这里按 RFC 9535 实现,结果适合本机调试,贴进代码前先确认那边库的行为。 为什么 XPath 不做完整版:完整实现要处理 13 条轴、命名空间、变量与一大票函数,是几千行;而浏览器自带的 `document.evaluate` 虽然现成,却要求算法碰 DOM —— 本站所有工具算法都是纯函数,碰了就没法在 Node 里测。所以这里在站内的轻量 HTML 解析器上实现最常用的那一层。 解析是容错的:用户粘进来的 HTML 常常缺闭合标签、少引号,这些都不该让整次查询失败(解析器与「HTML 转 Markdown」共用同一个)。

功能

  • 一套界面两种语法:XPath 走 HTML / XML,JSONPath 走 JSON
  • XPath 轴:子节点 `/` 与后代 `//`(抓取场景里用得最多的两条)
  • XPath 节点测试:标签名、`*`、`@属性名`、`text()`,标签名不区分大小写
  • XPath 谓词:`[1]`、`[last()]`、`[@a]`、`[@a="v"]`、`[contains(@a,"v")]`、`[starts-with(@a,"v")]` 等
  • JSONPath:`.key`、`["key"]`、`[*]`、`..` 递归下降、`[0]` 下标与并集、`[1:3]` 切片
  • JSONPath 过滤器:`[?(@.price < 100)]`,支持 `==` `!=` `<` `>` 比较、`&&` `||` 与括号
  • JSONPath 可额外输出每个结果在文档里的位置(`$` 开头的路径),方便写代码时直接引用
  • 四种输出:纯文本/值、HTML 源码、所在位置、只给数量
  • 位置谓词的语义与 XPath 一致:`//a[1]` 是「每个父节点下的第一个 a」
  • 每条结果带 1 起的序号并逐行可复制;复制对象时给格式化过的 JSON
  • 没匹配到时给一句说明,而不是一片空白
  • 不支持的写法明确报错,不会与「没匹配到」混淆
  • 畸形的 HTML 也能解析,不会因为缺个闭合标签就整次失败

使用方法

  1. 选语法:XPath(HTML / XML)还是 JSONPath(JSON)
  2. 粘贴源码或 JSON,写一条表达式,例如 //a/@href 或 $.store.book[*].title
  3. 选输出形式:纯文本/值、HTML 源码、所在位置,还是只给数量
  4. 结果实时更新,点某一行的复制按钮取走一项

常见问题

支持哪些 XPath 写法?
轴只有子节点 `/` 与后代 `//`;节点测试有标签名、`*`、`@属性`、`text()`;谓词有 `[1]`、`[last()]`、`[@a]`、`[@a="v"]`、`[text()="v"]`、`[contains(@a,"v")]`、`[starts-with(@a,"v")]`,以及两条用 `and` 连接;函数只有外层 `count(...)`。不在这个范围内的写法会明确报「不支持」 —— 比如 `position()>1`、`!=` 比较、`ancestor::` 这类轴、以及命名空间。报错而不是给空结果,是因为这两种情况的屏幕表现完全一样,而后者会让你去反复检查一个其实没错的选择器。
`//a[1]` 为什么选中了好几个?
因为它选的是「每个父节点下的第一个 `a`」,不是「整篇里的第一个 `a`」—— 这是 XPath 的明确规定(`//a` 等价于「任意节点的 a 子节点」,位置谓词在每一组里各算各的)。想要整篇第一个,用 `(//a)[1]`(本工具不支持这种括号写法)或 `//a[1]` 配合只取第一行结果。这个区别是 XPath 最常被误解的地方,所以工具里按标准语义实现,没有为了方便而改掉它。
能抓不到链接时为什么是空的?
先确认三件事:属性名有没有写错(`href` 而不是 `link`);链接是不是写在别的属性上(有些站用 `data-href` 或 `onclick`);页面内容是不是脚本渲染出来的 —— 工具解析的是你粘贴进来的源码,如果你的源码来自浏览器的「查看源代码」而内容是 JS 渲染的,那份源码里本来就没有这些元素,得从开发者工具的 Elements 面板里复制渲染后的 HTML。工具不会去请求那个网址,这一条是刻意的。
JSONPath 支持哪些写法?
根 `$`(可省)、子节点 `.key` 与 `['key']`、通配 `[*]` 与 `.*`、递归下降 `..`、下标与并集 `[0]`、`[0,2]`、切片 `[1:3]`、以及过滤表达式 `[?(@.price < 100)]`(支持存在性判断、`==` `!=` `<` `<=` `>` `>=` 比较、`&&` `||`、括号,以及取反 `!`)。不支持的会明确报错:函数扩展(`length()`、`count()`、`match()`、`search()`、`value()`)、正则、过滤器里以 `$` 开头的绝对路径。
为什么我的 JSONPath 结果和代码里跑出来的不一样?
因为 JSONPath 至今没有统一的标准。RFC 9535 到 2024 年才发布,此前 JavaScript 的 `jsonpath`、Python 的 `jsonpath-ng`、Java 的 Jayway 各写各的,分歧集中在三处:切片边界(`:3` 含不含第 3 项)、递归下降要不要包含自身(`$..a` 能不能选到最顶层那个 `a`)、以及过滤器的比较是否允许跨类型(`@.price < "10"` 拿字符串比数字)。这里一律按 RFC 9535:切片右开、递归下降包含自身、跨类型比较返回 false。所以这个工具适合在本机调试时确认路径写对了,贴进代码前先拿真实数据在目标库里验一遍。
「所在位置」输出是干什么用的?
它给每个匹配结果标出在文档里的路径,例如 `$.store.book[2].title`。写代码时常常是反过来 —— 你已经知道某个值长什么样,但要在结构里找到它的位置,好写死一条取值路径。直接输出值只能告诉你「有这几个」,输出位置才能告诉你「它们在哪」。注意路径里带特殊字符的键名会写成 `['a.b']` 的形式,这样它和 `.a.b` 的区别才保留下来。

相关工具