Вибір класу 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')
Гордон,



Відповідь @ Гордона небезпечна, якщо атрибут класу має значення "datetime", він також збігається. Відповідь користувача716736 є повнішою.
Niels Bom

Відповіді:


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 /


Що потрібно для нормалізації простору?
Фрік

"відповідь вище", ймовірно, стосується відповіді MrGlass.
LarsH

Чи можливо це <div class="foo\tbar">? Я маю на увазі назви класів, розділені табуляцією.
Заморожене полум'я

1
але <div class = "group-conditions" /> і <div class = "condition" /> однакові для $ x ('// div [містить (concat ("", normalize-space (@class), " ")," умова ")] '))
Мемке

1
@ testerjoe2 ти пробував //*[contains(concat(" ", normalize-space(@class), " "), " foo ")]?
Niels Bom

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 має статус Рекомендації щодо кандидатів .


Це не працює в останньому хромі. Поки це не спрацює, як нам обійти обмеження, яке // * [містить (@class, "foo")] також вибере будь-який клас, що містить foo, наприклад foobar, fooz тощо
MasterJoe


1

HTML дозволяє чутливі до регістру імена елементів та атрибутів, а потім клас - це розділений пробілами список назв класів. Тут ми перейдемо до imgтегу та classназваного date:

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

Дивіться також: CSS Selector в XPath перетворення


1

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