gkd 选择器层级关系:祖先、子孙与兄弟节点的定位写法
当目标节点自身没有可辨别的属性时,它的邻居往往很有特征。GKD 的关系选择器负责表达这种位置约束:官方定义它是「由关系操作符和关系表达式构成、用于连接两个属性选择器」的部分。
六种关系操作符
| 操作符 | 含义 | 示例 |
|---|---|---|
> | 祖先节点 | FrameLayout > TextView(TextView 的祖先是 FrameLayout) |
< | 直接子节点 | View < Button(View 的直接子节点里有 Button) |
<< | 子孙节点(任意深度) | View <<2 Button(Button 是 View 的第 2 层以内子孙) |
+ | 前置兄弟节点 | A + B(B 的前一个兄弟是 A) |
- | 后置兄弟节点 | A - B(B 的后一个兄弟是 A) |
-> | 查询过程中的之前节点 | C ->1 B > A(回到 B 的前序节点继续查) |
记忆方式:> < 是上下(祖先/子孙),+ - 是左右(兄弟),<< 是不限深度的子孙,-> 是「查到这里,掉头再查」的进阶用法。
关系表达式:不只是「相邻一个」
每个关系操作符后面可以跟元组表达式,精确描述「第几个」:
A +3 B:B 的前数第 3 个兄弟节点是 A;A +(2,3,5) B:A 在 B 的前置兄弟中排第 2、3 或 5 之一;A >(n) B:A 是 B 的任意祖先(无限元组);A <<2 B:A 在 B 的两代以内。
数字还支持多项式写法 an+b(类 CSS 的 nth-child),比如 (-n+4) 等价于 (1,2,3)。不过写规则时用到 (1) 或 (1,2) 的场合最多,复杂多项式属于进阶储备。
组合实战
回到选择器入门里的官方示例,现在可以完整读懂它了:
@[vid="menu"] < [vid="menu_container"] - [vid="dot_text_layout"] > [text^="广告"]
@声明最终目标是menu;<:menu 是 menu_container 的直接子节点;-:menu_container 的后置兄弟是 dot_text_layout;>:dot_text_layout 的子节点里有文字以「广告」开头的元素。
四个节点用三种关系串成一条证据链——只有这条链完整成立才命中,误匹配概率被压到极低。这就是「目标说不清自己,就让邻居作证」的落地形态。
官方的性能提示
选择器的匹配顺序是从右往左:FrameLayout > TextView 会先找 TextView,再验证它的父级是不是 FrameLayout。所以官方示例刻意把最有辨识度的条件(唯一 id、精确文字)放在表达式最右侧,先缩小候选集再验证关系,查询更快。
官方还给了个等价性示例:@LinearLayout > TextView[id=...][text=不感兴趣] 与「先找 TextView 再 <n LinearLayout」目标一致,但前者(右端条件更强)算法复杂度更低。
进阶组合
单个关系链不够用时,选择器之间还能做逻辑运算:(A + B) || (M > N) 表示满足任一即可(短路求值),(A + B) && (M > N) 要求同时满足,!(A + B) 取反。单条选择器必须用 () 包裹后再参与逻辑运算,且 && 优先级高于 ||。