2.1. Overview (概览)
2.1. Overview (概览)
JSONPath expression (表达式) 是一个字符串, 作用于 JSON 值 (query argument (查询实参)) 时, 选择实参中的零个或多个节点, 并将这些节点作为 nodelist 输出.
查询必须使用 UTF-8 编码. 本文档给出的查询文法假定其 UTF-8 形式先按 [RFC3629] 解码为 Unicode scalar values; 产生等价结果的实现方式亦可.
用作 JSONPath 查询的字符串需要 well-formed (良构) 且 valid (有效). 若字符串符合本文档的 ABNF 语法, 则为 well-formed JSONPath 查询. Well-formed JSONPath 查询若还满足本文档提出的两项语义要求, 则为 valid:
-
JSONPath 查询中与 JSONPath 处理相关的整数 (例如 index 值与 step) 必须落在 Internet JSON (I-JSON) 所定义的可精确表示整数范围内 (见 [RFC7493] 第 2.2 节), 即闭区间 [-(2^53)+1, (2^53)-1].
-
Function extensions (函数扩展) 的使用必须 well-typed (类型良好), 见第 2.4.3 节.
JSONPath 实现对于任何非 well-formed 且 valid 的查询必须报错. Well-formedness 与 validity 与查询所作用的 JSON 值无关. 将查询作用于值时, 不得再产生与查询 well-formedness / validity 相关的错误. 从而将查询本身的良构/有效性问题与可能实际源于数据缺陷的不匹配清晰分开.
Valid 查询所期望的结构与数据中找到的结构不匹配时, 可能导致空的查询结果; 这可能出乎意料并提示任一侧存在缺陷. JSONPath 实现因此可能希望向应用开发者提供有助于定位空结果原因的诊断信息.
显然, 执行 JSONPath 查询时实现仍可能失败, 例如因资源耗尽, 但本文档不对其建模. 然而, 实现绝对不能静默故障. 具体而言, 若对 structured value 求值 valid JSONPath 查询时, 值过大以致无法正确处理查询 (例如需要处理落在可精确表示范围之外的数字), 实现必须提供溢出指示.
(熟悉 HTTP 错误模型的读者在思考 well-formedness 与 validity 时可联想到 400 类错误; 资源耗尽及相关错误可类比 500 类错误.)
2.1.1. Syntax (语法)
在语法上, JSONPath 查询由 root identifier ($) 组成, 它表示包含 query argument 根节点的 nodelist, 后接可能为空的 segments (片段) 序列.
jsonpath-query = root-identifier segments
segments = *(S segment)
B = %x20 / ; Space
%x09 / ; Horizontal tab
%x0A / ; Line feed or New line
%x0D ; Carriage return
S = *B ; optional blank space
Segment 的语法与语义在第 2.5 节定义.
2.1.2. Semantics (语义)
本文档中 JSONPath 查询的语义定义所需结果, 并不规定实现的内部工作方式. 本文档可能以过程性步骤描述语义; 然而, 此类描述作为规范仅在于任何实现必须产生相同结果, 并不要求实现者使用相同算法.
语义为: 对值 (query argument) 执行 valid 查询, 产生 nodelist (即值中零个或多个节点的列表).
查询为 root identifier 后接零个或多个 segment 的序列; 每个 segment 作用于前一个 root identifier 或 segment 的结果, 并为下一个 segment 提供输入. 这些结果与输入均为 nodelist 形式.
Root identifier 产生的 nodelist 包含单个节点 (即 query argument). 最后一个 segment 产生的 nodelist 作为查询结果呈现. 视具体 API 而定, 可能呈现为节点处 JSON 值的数组, Normalized Paths 引用节点的数组, 或两者兼有, 或实现期望的其他表示. 注意: 空 nodelist 是合法的查询结果.
Segment 依次对其输入 nodelist 中的每个节点运算, 将所得 nodelist 按其所源自的输入 nodelist 顺序拼接, 形成该 segment 的结果. 同一节点可被选择多次, 在 nodelist 中出现相应次数. 不去除重复节点.
语法上 valid 的 segment 在执行查询时不得产生错误. 这意味着某些可能被视为错误的操作, 例如使用超出数组范围的 index, 仅导致选中节点变少. (关于该性质的更多讨论见第 2.1 节引言.)
在此方法下, 若任一 segment 产生空 nodelist, 则整个查询产生空 nodelist.
若查询语义允许实现产生多种可能排序, 特定实现可能在多次运行查询时产生不同排序.
2.1.3. Example (示例)
考虑以下示例. 查询实参为 {"a":[{"b":0},{"b":1},{"c":2}]}, 查询 $.a[*].b 选择如下节点列表 (此处用其值表示): 0, 1.
查询由 $ 及三个 segment 组成: .a, [*], .b.
首先, $ 产生仅含 query argument 的 nodelist.
接着, .a 从任意 object 输入节点选择与成员名 "a" 对应的成员值的节点. 结果仍是含单个节点的列表: [{"b":0},{"b":1},{"c":2}].
接着, [*] 从输入 array 节点选择所有元素. 结果是三个节点的列表: {"b":0}, {"b":1}, {"c":2}.
最后, .b 从具有成员名 b 的任意 object 输入节点选择与该名称对应的成员值的节点. 结果是含 0, 1 的列表. 这是三个列表的拼接: 两个长度为一分别含 0 与 1, 一个长度为零.