Есть решение для перебора. Я продемонстрирую два атрибута вместо трех.
(
//web:link[@text != 'Login' and @href != 'Login.php'
and not(//web:link[@text = 'Login' or @href = 'Login.php'])]
| //web:link[@text != 'Login' and @href = 'Login.php'
and not(//web:link[@text = 'Login'])]
| //web:link[@text = 'Login' and @href != 'Login.php'
and not(//web:link[@text = 'Login' and @href = 'Login.php'])]
| //web:link[@text = 'Login' and @href = 'Login.php']
)[1]
То есть, выберите все ссылки, где ни один атрибут не соответствует, но только если нет ссылки, которая имеет лучшее соответствие. Затем выберите все ссылки, которые имеют меньшее соответствие атрибута, но только в том случае, если нет ссылок с более высоким соответствием атрибута. Ссылки выбора, где только первый атрибут соответствует, но только если нет ссылок, где оба атрибута совпадают. Затем выберите ссылки, где оба атрибута совпадают. Только одна из этих четырех конъюнктов будет непустой, поэтому оператор "|
" фактически никогда ничего не объединяет. Наконец, выберите первую ссылку в порядке документа, если какой-либо из этих наборов узлов содержал более одного элемента.
Причина, по которой я сделал только два атрибута вместо трех, заключается в том, что я не хотел печатать все восемь случаев. Вы можете пропустить первый случай, если вас не интересуют какие-либо ссылки, если хотя бы один из атрибутов не соответствует.
В такой ситуации вам может быть лучше просто выбрать все кандидатов в гораздо более простой запрос, который Джефф показал , а затем использовать другой код для ранжирования результатов впоследствии, где Вы можете более легко использовать итерацию и переменные, чтобы выбрать лучшего кандидата.
Если вы можете использовать XPath 2 , то вы можете использовать оператор запятой (или concat
функция ) для объединения последовательностей узлов (которые заменяют собой узел-множество). Попробуйте это, например:
(
//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' 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]
)[1]
Кроме того, вот простой способ присвоить ранг каждой ссылке, что делает сравнение их довольно простым. Представьте себе битовое поле, один бит для каждого атрибута, который вы хотите проверить. Если первый атрибут совпадает, установите самый левый бит, иначе оставьте его неустановленным. Если второй атрибут совпадает, установите следующий старший значащий бит и т. Д. Итак, для вашего примера вы получите следующие битовые значения:
011 link A: text='Sign In', href='Login.php', index=0
100 link B: text='Login', href='Signin.php', index=15
110 link C: text='Login', href='Login.php', index=22
Чтобы выбрать лучшее соответствие, обрабатывайте битовые поля как двоичные числа. Ссылка A имеет оценку 3, ссылка B - 4, а ссылка C - 6. (Это немного напоминает, как определяется специфичность CSS-селекторов .) Это способ моделирования критериев упорядочения, но теперь, когда я все это напечатал, я не совсем понимаю, что это приводит к какому-либо краткому решению в XPath.