跳到主要内容

2.5. Segments (片段)

2.5. Segments (片段)

对输入 nodelist 中的每个节点, segment 对该节点应用一个或多个 selector, 将每个 selector 的结果拼接为按输入节点分的 per-input-node nodelist, 再按输入 nodelist 顺序拼接为单一 segment 结果 nodelist.

查询中 segment 越多, 结果 nodelist 中节点在输入值中的深度越大:

  • 含 N 个 segment 的查询, N >= 0, 产生深度在输入值中至少为 N 的节点的 nodelist.

  • 含 N 个 segment 的查询, N >= 0, 且全部为 child segment (第 2.5.1 节), 产生深度在输入值中恰好为 N 的节点的 nodelist.

Segment 有两种: child segment 与 descendant segment.

segment             = child-segment / descendant-segment

各类 segment 的语法与语义见下文.

2.5.1. Child Segment (子片段)

2.5.1.1. Syntax (语法)

Child segment 由方括号括起的非空逗号分隔 selector 序列组成.

单个 wildcard 或 name selector 时也提供简写记法.

child-segment       = bracketed-selection /
("."
(wildcard-selector /
member-name-shorthand))

bracketed-selection = "[" S selector *(S "," S selector) S "]"

member-name-shorthand = name-first *name-char
name-first = ALPHA /
"_" /
%x80-D7FF /
; skip surrogate code points
%xE000-10FFFF
name-char = name-first / DIGIT
DIGIT               = %x30-39              ; 0-9
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z

., 直接由 wildcard-selector 构成的 child-segment, 是 [] 的简写.

., 由 member-name-shorthand 构成的 child-segment, 是 [''] 的简写. 注意: 仅可用于由 member-name-shorthand ABNF 规则所允许字符组成的成员名. 例如 $.foo.bar 是 $['foo']['bar'] 的简写 (但不是 $['foo.bar'] 的简写).

2.5.1.2. Semantics (语义)

Child segment 包含 selector 序列, 每个 selector 选择输入值的零个或多个子节点.

不同种类的 selector 可出现在同一 child segment 内.

对输入 nodelist 中的每个节点, child segment 的结果 nodelist 为其各 selector 的 nodelist 按列表中出现顺序的拼接. 注意: 被多个 selector 匹配的节点在 nodelist 中保留相应次数.

Selector 可产生多种可能顺序时, child segment 中该 selector 的每次出现都可能产生不同顺序的 nodelist.

总之, child segment 向输入值的结构再深入一层.

2.5.1.3. Examples (示例)

JSON:

["a", "b", "c", "d", "e", "f", "g"]

Queries:

QueryResultResultComment
Paths
$[0,"a"$[0]Index
3]"d"$[3]
$[0:2,"a"$[0]Slice 与
5]"b"$[1]index
"f"$[5]
$[0,"a"$[0]重复
0]"a"$[0]

表 15: Child Segment 示例

2.5.2. Descendant Segment (后代片段)

2.5.2.1. Syntax (语法)

Descendant segment 由双点 .. 后接 child segment (使用方括号记法) 组成.

也提供与 child segment 简写形式对应的简写.

descendant-segment  = ".." (bracketed-selection /
wildcard-selector /
member-name-shorthand)

.., 直接由 wildcard-selector 构成的 descendant-segment, 是 ..[] 的简写.

.., 由 member-name-shorthand 构成的 descendant-segment, 是 ..[''] 的简写. 注意: 与 child-segment 类似简写一样, 仅适用于 member-name-shorthand 规则允许的字符组成的成员名.

注意: 单独的 .. 不是合法 segment.

2.5.2.2. Semantics (语义)

Descendant segment 产生输入值的零个或多个后代节点.

对输入 nodelist 中的每个节点, descendant selector 访问输入节点及其每个后代, 满足:

  • 任意 array 的节点按 array 顺序访问, 且

  • 节点在其后代之前访问.

Object 子节点的访问顺序不予规定, 因为 JSON object 无序.

设 descendant segment 形如 ..[<selectors>] (将任意简写转为方括号记法后), 按访问顺序的节点为 D1, ..., Dn (n >= 1). 注意: D1 为输入值.

对每个满足 1 <= i <= n 的 i, 将 nodelist Ri 定义为对节点 Di 应用 child segment [<selectors>] 的结果.

对输入 nodelist 中的每个节点, descendant segment 的结果为 R1, ..., Rn 按该顺序的拼接. 再按输入 nodelist 顺序拼接这些结果, 形成 segment 的结果.

总之, descendant segment 向每个输入值的结构深入一层或多层.

2.5.2.3. Examples (示例)

JSON:

{
"o": {"j": 1, "k": 2},
"a": [5, 3, [{"j": 4}, {"k": 6}]]
}

Queries:

(注意第四个示例可用两个等价查询表达, 表 16 中合并为一行而非两行几乎相同的行.)

QueryResultResult PathsComment
$..j1$['o']['j']Object
4$['a'][2][0]['j']
$..j4$['a'][2][0]['j']另一种
1$['o']['j']结果
$..[0]5$['a'][0]Array
{"j": 4}$['a'][2][0]
$..[*]{"j": 1,$['o']所有值
or"k": 2}$['a']
$..*[5, 3,$['o']['j']
[{"j": 4},$['o']['k']
{"k": 6}]]$['a'][0]
1$['a'][1]
2$['a'][2]
5$['a'][2][0]
3$['a'][2][1]
[{"j": 4},$['a'][2][0]['j']
{"k": 6}]$['a'][2][1]['k']
{"j": 4}
{"k": 6}
4
6
$..o{"j": 1,$['o']访问了
"k": 2}输入值
$.o..[*,1$['o']['j']非确定
*]2$['o']['k']顺序
2$['o']['k']
1$['o']['j']
$.a..[0,5$['a'][0]多个
1]3$['a'][1]segment
{"j": 4}$['a'][2][0]
{"k": 6}$['a'][2][1]

表 16: Descendant Segment 示例

注意: 上文 $..[] 与 $.. 示例的结果顺序不予保证, 但:

  • {"j": 1, "k": 2} 必须出现在 1 与 2 之前,

  • [5, 3, [{"j": 4}, {"k": 6}]] 必须出现在 5, 3 与 [{"j": 4}, {"k": 6}] 之前,

  • 5 必须出现在 3 之前, 3 必须出现在 [{"j": 4}, {"k": 6}] 之前,

  • 5 与 3 必须出现在 {"j": 4}, 4, {"k": 6} 与 6 之前,

  • [{"j": 4}, {"k": 6}] 必须出现在 {"j": 4} 与 {"k": 6} 之前,

  • {"j": 4} 必须出现在 {"k": 6} 之前,

  • {"k": 6} 必须出现在 4 之前, 且

  • 4 必须出现在 6 之前.

查询 $.o..[*, *] 的示例表明, selector 在 descendant segment 中每次出现都可能产生不同顺序的 nodelist.

查询 $.a..[0, 1] 的示例表明, child segment [0, 1] 依次应用于每个节点 (而非某些不符合本规范的 JSONPath 实现那样每个 selector 只遍历节点一次).