
本文介绍如何用单条 xpath 表达式实现“优先匹配某条件,若不存在则回退到另一条件”,并确保仅返回文档中第一个匹配节点(按文档顺序),避免重复执行 evaluate 调用。
在 XPath 中,|(联合运算符)会合并两个节点集,并自动按文档顺序去重排序。因此,表达式 //*[@selected]/@value|//text() 本身已将所有匹配的 @value 属性节点和文本节点混合后按其在 DOM 中的实际位置升序排列。此时只需在外层添加 [1] 即可精准获取整个联合结果中的第一个节点——这正是“优先取 [@selected]/@value,无则取 //text() 中最早出现者”的语义实现。
✅ 正确写法(XPath 1.0 兼容,浏览器原生支持):
(//*[@selected]/@value|//text())[1]
该表达式在 document.evaluate 中可直接使用,无需 JavaScript 分支逻辑:
function xpathFirst(path) {
const result = document.evaluate(
path,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
);
return result.singleNodeValue;
}
const value = xpathFirst('(//*[@selected]/@value|//text())[1]');
// 若存在带 selected 属性的元素,返回其 value 属性值(字符串);
// 否则返回文档中第一个文本节点(Text 对象,需 .nodeValue 获取内容)⚠️ 注意事项:
- @value 是属性节点,//text() 返回文本节点,二者类型不同;singleNodeValue 返回的是对应节点对象(如 Attr 或 Text),如需字符串值,请统一调用 .value(Attr)或 .nodeValue(Text),或改用 XPathResult.STRING_TYPE 配合 .stringValue(但注意:STRING_TYPE 对空结果返回空字符串,且不支持直接获取属性/文本混合的字符串,故推荐先取节点再判断类型)。
- 若需更复杂的多级 fallback(如 A → B → C),XPath 1.0 无法优雅表达,建议升级至 XPath 3.1(如通过 SaxonJS):
(//*[@selected]/@value, //input/@placeholder, //div/text())[1]
逗号表示序列拼接(保持顺序,不排序),更符合“严格优先级”语义。
? 总结:对于双条件 fallback 场景,(A|B)[1] 是 XPath 1.0 下简洁、高效、标准兼容的最佳实践;它利用联合运算符的文档顺序特性,以声明式语法替代命令式分支,显著提升可读性与可维护性。










