Как я могу сопоставить атрибут, содержащий определенную строку?

У меня возникает проблема выбора узлов по атрибуту, когда атрибуты содержат более одного слова. Например:

<div class="atag btag" />

Это мое выражение xpath:

//*[@class='atag']

Выражение работает с

<div class="atag" />

но не для предыдущего примера. Как я могу выбрать <div>?

Ответ 1

Это выберет их все независимо от положения атрибутов

//div[contains(@class, 'atag') and contains(@class ,'btag')]

Ответ 2

Ответ mjv - хороший старт, но не будет выполнен, если atag не является первым указанным именем.

Обычный подход является довольно громоздким:

//*[contains(concat(' ', @class, ' '), ' atag ')]

это работает до тех пор, пока классы разделяются только пробелами, а не другими формами пробелов. Это почти всегда так. Если это может быть не так, вы должны сделать его еще более громоздким:

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]

(Выбор по типам, подобным пространству разделенных пробелами, является таким распространенным случаем, что удивительно, что для него нет определенной функции XPath, например CSS3 '[class ~ = "atag" ]'.)

Ответ 3

РЕДАКТИРОВАТЬ: см. решение bobince, которое использует содержит, а не start-with, а также трюк, чтобы гарантировать, что сравнение выполняется на уровне полного токена (чтобы шаблон "atag" не найден как часть другого "тега" ).

"atag btag" является нечетным значением для атрибута класса, но тем не менее, попробуйте:

//*[starts-with(@class,"atag")]

Ответ 4

A 2.0 XPath, который работает:

//*[tokenize(@class,'\s+')='atag']

или с переменной:

//*[tokenize(@class,'\s+')=$classname]

Ответ 5

Помните, что ответ bobince может быть слишком сложным, если вы можете предположить, что интересующее вас имя класса не является подстрокой другого возможного имени класса. Если это так, вы можете просто использовать подстроку, используя функцию contains. Следующее будет соответствовать любому элементу, класс которого содержит подстроку 'atag':

//*[contains(@class,'atag')]

Если вышеприведенное предположение не выполняется, соответствие подстроки будет соответствовать элементам, которые вы не собираетесь использовать. В этом случае вам нужно найти границы слов. Используя разделители пробелов, чтобы найти границы имени класса, bobince второй ответ находит точные соответствия:

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]

Это будет соответствовать atag, а не matag.

Ответ 6

попробуйте следующее: //[contains(@class, 'atag')]

Ответ 7

Чтобы добавить ответ bobince... Если какой-либо инструмент/библиотека, используемая вами, использует Xpath 2.0, вы также можете сделать это:

//*[count(index-of(tokenize(@class, '\s+' ), $classname)) = 1]

count(), по-видимому, необходимо, потому что index-of() возвращает последовательность каждого индекса, в которой она имеет совпадение в строке.

Ответ 8

Вы можете попробовать следующее

By.CssSelector("div.atag.btag")

Ответ 9

Для ссылок, содержащих общий url, необходимо консоль в переменной. Затем выполните его последовательно.

webelements allLinks=driver.findelements(By.xpath("//a[contains(@href,'http://122.11.38.214/dl/appdl/application/apk')]"));
int linkCount=allLinks.length();
for(int i=0; <linkCount;i++)
{
    driver.findelement(allLinks[i]).click();
}

Ответ 10

Обычно я использую CSS-селектора, если имеется более одного слова, разделенных пробелом (даже если я могу использовать ID):

.atag.btag

Первая точка означает - это класс, все после него - значение класса (просто замените все пробелы на периоды)

Если это идентификатор: <div id="atag btag" /> Вы можете пойти с CSS: #atag.btag