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


87

Я хочу выбрать только класс с именем .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." ";
}

2
а что насчет кусочка html? (Предпочитаю показывать нам вывод simpleXml из asXML (), поскольку он ближе к xpath)
SergeS

если вам нужно сделать несколько занятийcontains(@class, 'date')
Гордон



Ответ @Gordon опасен, если атрибут класса "datetime" также будет совпадать. Ответ user716736 более полный.
Нильс Бом

Ответы:


242

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

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

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- in-xpathxslt /


Зачем нужно normalize-space?
Freek

"ответ выше", вероятно, относится к MrGlass.
LarsH 09

Это возможно <div class="foo\tbar">? Я имею в виду, имена классов разделены табуляцией.
Frozen Flame

1
но <div class = "group-conditions" /> и <div class = "condition" /> одинаковы для $ x ('// div [contains (concat ("", normalize-space (@class), " ")," condition ")] ')
Memke 09

1
@ testerjoe2 пробовали //*[contains(concat(" ", normalize-space(@class), " "), " foo ")]?
Нильс Бом

11

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

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


7

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

Пример:

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

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


Примечание. На сегодняшний день (13.12.2016) XPath 3.1 имеет статус кандидата в рекомендации .


Это не работает в последней версии Chrome. Пока это не сработает, как нам обойти ограничение, согласно которому // * [contains (@class, "foo")] также будет выбирать любой класс, содержащий foo, например foobar, fooz и т. Д.
MasterJoe

3

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

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

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


к сожалению, по состоянию на 12.06.2017 это не реализовано в Chrome. на основе en.wikipedia.org/wiki/ ... кажется, чего не хватает практически по всем направлениям
JonnyRaa

1

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

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

Смотрите также: CSS Selector to XPath преобразование


1

ОСТОРОЖНО ЗНАКОВ МИНУС В ШАБЛОНЕ !!! Если вы запрашиваете "мой собственный класс" в 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.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.