有一个蛮力解决方案。我将演示两个属性而不是三个。
(
//web:link[@text != 'Login' 和 @href != 'Login.php'
而不是(//web:link[@text = 'Login' or @href = 'Login.php'])]
| //web:link[@text != 'Login' 和 @href = 'Login.php'
而不是(//web:link[@text = 'Login'])]
| //web:link[@text = 'Login' 和 @href != 'Login.php'
而不是(//web:link[@text = 'Login' and @href = 'Login.php'])]
| //web:link[@text = 'Login' 和 @href = 'Login.php']
)[1]
也就是说,选择两个属性都不匹配的所有链接,但前提是没有更好匹配的链接。然后选择所有具有较小属性匹配的链接,但仅当没有与高级属性匹配的链接时。只有第一个属性匹配的选择链接,但前提是没有两个属性都匹配的链接。然后选择两个属性都匹配的链接。这四个连词中只有一个是非空的,因此“|”运算符实际上从未组合任何内容。最后,选择文档顺序中的第一个链接,以防其中任何一个节点集包含多个元素。
我只做两个属性而不是三个的原因是因为我不想输入所有八个案例。如果您对任何链接不感兴趣,则可以省略第一种情况,除非至少有一个属性匹配。
在这种情况下,您最好选择所有 the much simpler query Jeff showed 中的候选者,然后使用其他代码对结果进行排名,这样您可以更轻松地使用迭代和变量选择最佳候选人。
如果您可以使用 XPath 2,那么您可以使用 the comma operator(或 the concat function)加入节点序列(取代节点集)。试试这个,例如:
(
//web:link[@text = 'Login' 和 @href = 'Login.php' 和 @index = 0]
, //web:link[@text = 'Login' and @href = 'Login.php' and @index != 0]
, //web:link[@text = 'Login' and @href != 'Login.php' and @index = 0]
, //web:link[@text = 'Login' and @href != 'Login.php' and @index != 0]
, //web:link[@text != 'Login' and @href = 'Login.php' and @index = 0]
, //web:link[@text != 'Login' and @href = 'Login.php' and @index != 0]
, //web:link[@text != 'Login' 和 @href != 'Login.php' 和 @index = 0]
, //web:link[@text != 'Login' and @href != 'Login.php' and @index != 0]
)[1]
顺便说一句,这里有一种为每个链接分配排名的简单方法,这使得比较它们变得非常简单。想象一个位字段,您要检查的每个属性一个位。如果第一个属性匹配,则设置最左边的位,否则不设置。如果第二个属性匹配,则设置下一个最高有效位等。因此,对于您的示例,您将获得以下位值:
011链接A:text='登录',href='Login.php',索引=0
100 链接 B: text='Login', href='Signin.php', index=15
110 链接 C: text='Login', href='Login.php', index=22
要选择最佳匹配,请将位字段视为二进制数。链接 A 的得分为 3,链接 B 的得分为 4,链接 C 的得分为 6。(这有点让人想起 specificity of CSS selectors 的确定方式。)这是一种对排序标准进行建模的方法,但是现在我已经全部输入了,我不太明白它会导致 XPath 中的任何简明解决方案。