Wybieranie klasy css za pomocą xpath

87

Chcę wybrać tylko własną klasę o nazwie .date

Z jakiegoś powodu nie mogę tego uruchomić. Jeśli ktoś wie, co jest nie tak z moim kodem, będzie to bardzo cenne.

@$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." ";
}
Teddy13
źródło
2
a co z kawałkiem html? (Wolę pokazać nam wyjście simpleXml z asXML (), ponieważ jest bliżej xpath)
SergeS
jeśli jest wiele zajęć, które musisz zrobićcontains(@class, 'date')
Gordon
Odpowiedź @ Gordona jest niebezpieczna, jeśli atrybut klasy to „datetime”, również by pasował. Odpowiedź użytkownika716736 jest bardziej kompletna.
Niels Bom

Odpowiedzi:

242

Chcę napisać kanoniczną odpowiedź na to pytanie, ponieważ powyższa odpowiedź ma problem.

Nasz problem

CSS selektor:

.foo

wybierze dowolny element, który ma klasę foo .

Jak to robisz w XPath?

Chociaż XPath jest potężniejszy niż CSS, XPath nie ma natywnego odpowiednika selektora klas CSS . Jest jednak rozwiązanie.

Właściwy sposób, aby to zrobić

Odpowiedni selektor w XPath to:

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

Funkcja normalize-space usuwa początkowe i końcowe białe znaki (a także zastępuje sekwencje białych znaków pojedynczą spacją).

(W bardziej ogólnym sensie) jest to również odpowiednik selektora CSS:

*[class~="foo"]

który będzie pasował do każdego elementu, którego wartością atrybutu klasy jest lista wartości oddzielonych białymi znakami, z których jedna jest dokładnie równa foo .

Kilka oczywistych, ale złych sposobów na zrobienie tego

Selektor XPath:

//*[@class="foo"]

nie działa! ponieważ na przykład nie będzie pasował do elementu, który ma więcej niż jedną klasę

<div class="foo bar">

Nie będzie również pasować, jeśli wokół nazwy klasy znajduje się dodatkowa spacja:

<div class="  foo ">

„Ulepszony” selektor XPath

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

też nie działa! ponieważ na przykład błędnie dopasowuje elementy z klasą foobar

<div class="foobar">

Podziękowania dla tego gościa, który był najwcześniej opublikowanym rozwiązaniem tego problemu, jakie znalazłem w sieci: http://dubinko.info/blog/2007/10/01/simple-parsing-of-space-seprated-attributes- in-xpathxslt /

user716736
źródło
Jaka jest potrzeba normalizacji przestrzeni?
Freek,
„powyższa odpowiedź” prawdopodobnie odnosi się do MrGlass.
LarsH
Czy to możliwe <div class="foo\tbar">? Mam na myśli nazwy klas oddzielone tabulatorem.
Frozen Flame
1
ale <div class = "group-conditions" /> i <div class = "condition" /> to to samo dla $ x ('// div [zawiera (concat ("", normalize-space (@class), " ")," stan ")] ')
Memke
1
@ testerjoe2 próbowałeś //*[contains(concat(" ", normalize-space(@class), " "), " foo ")]?
Niels Bom
11

//[@class="date"] nie jest prawidłową ścieżką xpath.

Spróbuj //*[@class="date"], a jeśli wiesz, że to obraz,//img[@class="date"]

MrGlass
źródło
7

XPath 3.1 wprowadza funkcję zawierającą token i tym samym ostatecznie rozwiązuje ten problem „oficjalnie”. Jest przeznaczony do obsługi zajęć .

Przykład:

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

Ta funkcja zapewnia prawidłową obsługę białych znaków (nie tylko (U + 0020)), działa w przypadku powtarzania się nazw klas i generalnie obejmuje skrajne przypadki.


Uwaga: na dzień dzisiejszy (13.12.2016) XPath 3.1 ma status rekomendacji dla kandydatów .

Robin Pokorny
źródło
Nie działa w dzisiejszym najnowszym chrome. Dopóki to nie zadziała, jak obejść ograniczenie, które // * [zawiera (@class, "foo")] wybierze również każdą klasę zawierającą foo, taką jak foobar, fooz itp.
MasterJoe
1

HTML zezwala na rozróżnianie wielkości liter w nazwach elementów i atrybutów, a klasa jest listą nazw klas oddzielonych spacjami. Tutaj idziemy do imgtagu i classnazwanego date:

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

Zobacz także: Selektor CSS do konwersji XPath

hakre
źródło
1

UWAŻAJ NA ZNAKI MINUS W WZORNIKU !!! Jeśli pytasz o „my-ownclass” w 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.
Vlado
źródło