
使用 xpath 表达式 `(//*[@selected]/@value|//text())[1]` 可简洁实现“优先匹配 `@selected` 属性值,不存在时回退到任意文本节点”的逻辑,无需 javascript 多次调用 `evaluate`。
在 XPath 中,| 运算符用于合并多个节点集,其结果是按文档顺序(document order)去重并排序后的节点集合。因此,(//*[@selected]/@value|//text())[1] 的含义是:
- 先收集所有满足 //*[@selected]/@value 的属性节点(即任意位置带 selected 属性的元素的 value 值);
- 再收集所有 //text() 文本节点;
- 将二者合并为一个节点集,并按 HTML/XML 文档中实际出现顺序排列;
- 最后取第一个节点([1])——这天然保证了:若存在 @selected 对应的 @value,且它在文档中早于所有 //text() 节点,则返回它;否则返回文档中最靠前的文本节点。
✅ 正确示例(HTML 片段):
Normalfallback text
执行 (//*[@selected]/@value|//text())[1] 将返回 "primary"(来自 的 value 属性),因其节点在文档中位于 fallback text 之前。
⚠️ 注意事项:
- [1] 作用于整个联合结果集,不是分别对左右两侧取 [1](区别于某些误解);
- //text() 匹配所有文本节点(包括空白、换行),如需更精确控制,建议限定为非空文本://text()[normalize-space()];
- 若需支持更复杂的多级 fallback(如 A → B → C),XPath 2.0+ 可用序列构造器配合 ? 安全调用(如 SaxonJS 中):
(//*[@selected]/@value, //*[contains(@class,'main')]/@data-id, //title/text())[1]
- 浏览器原生 document.evaluate() 仅支持 XPath 1.0,不支持逗号序列语法(如 (A,B)[1]),因此推荐使用 (A|B)[1] 形式以确保兼容性;若需 XPath 3.1 功能(如函数式 fallback),可引入 SaxonJS。
? 总结:用 (expr1|expr2)[1] 替代多次 evaluate 调用,既简洁又高效,是 XPath 条件优先匹配的经典实践。










