Выбор класса css с помощью xpath

Я хочу выбрать только класс по своему названию .date

По какой-то причине я не могу заставить это работать. Если кто-то знает, что не так с моим кодом, это было бы очень признательно.

@$doc = new DOMDocument(); @$doc->loadHTML($html); $xml = simplexml_import_dom($doc); // just to make xpath more simple $images = $xml->xpath('//[@class="date"]'); foreach ($images as $img) { echo $img." "; } 

Я хочу написать канонический ответ на этот вопрос, потому что ответ выше имеет проблему.

Наша проблема

Селектор CSS :

 .foo 

выберет любой элемент, который имеет класс foo .

Как вы это делаете в XPath?

Хотя XPath более мощный, чем CSS, XPath не имеет собственного эквивалента селектора классов CSS . Однако есть решение.

Правильный способ сделать это

Эквивалентный селектор в XPath :

 //*[contains(concat(" ", normalize-space(@class), " "), " foo ")] 

Функция normalize-space разделяет начало и конец пробела (а также заменяет последовательности символов пробелов на одно пространство).

(В более общем смысле) это также эквивалент селектора CSS:

 *[class~="foo"] 

который будет соответствовать любому элементу, значение атрибута класса которого представляет собой список значений, разделенных пробелами, один из которых точно равен foo .

Несколько очевидных, но неправильных способов сделать это

Селектор XPath:

 //*[@class="foo"] 

не работает! потому что он не будет соответствовать элементу, который имеет более одного класса, например

 <div class="foo bar"> 

Он также не будет соответствовать, если есть дополнительные пробелы вокруг имени класса:

 <div class=" foo "> 

«Улучшенный» селектор XPath

 //*[contains(@class, "foo")] 

тоже не работает! потому что он неправильно сопоставляет элементы с классом foobar , например

 <div class="foobar"> 

Кредит относится к этому человеку, который был самым ранним опубликованным решением этой проблемы, которое я нашел в Интернете: http://dubinko.info/blog/2007/10/01/simple-parsing-of-space-seprated-attributes- в-xpathxslt /

//[@class="date"] не является допустимым xpath.

Попробуйте //*[@class="date"] , или если вы знаете, что это изображение, //img[@class="date"]

XPath 3.1 вводит функцию contains-token и, таким образом, окончательно решает это «официально». Он предназначен для поддержки классов .

Пример:

//*[contains-token(@class, "foo")]

Эта функция гарантирует, что пустое пространство (не только (U + 0020)) обрабатывается правильно, работает в случае повторения имени класса и обычно закрывает краевые случаи.


Примечание. На сегодняшний день (2016-12-13) XPath 3.1 имеет статус Рекомендации кандидата .

В XPath 2.0 вы можете:

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

как заявил Кристиан Вейск в: https://cweiske.de/tagebuch/XPath%3A%20Select%20element%20by%20class.htm

HTML позволяет вводить без учета регистра элементы и имена атрибутов, а затем класс – это список разделенных пробелами имен классов. Здесь мы идем для тега img и class именем date :

 //*['IMG' = translate(name(.), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')]/@*['CLASS' = translate(name(.), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') and contains(concat(' ', normalize-space(.), ' '), concat(' ', 'date', ' '))] 

См. Также: CSS-селектор для преобразования XPath

ОСТОРОЖНО МИНУС ЗНАКИ В ШАБЛОНЕ !!! Если вы запрашиваете «my-ownclass» в DOM:

 <ul class="my-ownclass"><li>...</li></ul> <ul class="someother"><li>...</li></ul> <ul><li>...</li></ul> $finder = new DomXPath($dom); $nodes = $finder->query(".//ul[contains(@class, 'my-ownclass')]"); // This will NOT behave as expected! This will strangely match all the <ul> elements in DOM. $nodes = $finder->query(".//ul[contains(@class, 'ownclass')]"); // This will match the element.