Memilih kelas css dengan xpath

87

Saya hanya ingin memilih kelas sendiri yang disebut .date

Untuk beberapa alasan, saya tidak bisa membuat ini bekerja. Jika ada yang tahu apa yang salah dengan kode saya, itu akan sangat dihargai.

@$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
sumber
2
dan bagaimana dengan bagian dari html? (Lebih suka menunjukkan kepada kami output simpleXml dari asXML () karena lebih dekat ke xpath)
SergeS
jika ada beberapa kelas yang perlu Anda lakukancontains(@class, 'date')
Gordon
Jawaban @ Gordon berbahaya, jika atribut kelasnya adalah "datetime", itu juga akan cocok. Jawaban user716736 lebih lengkap.
Niels Bom

Jawaban:

242

Saya ingin menulis jawaban kanonik untuk pertanyaan ini karena jawaban di atas memiliki masalah.

Masalah kita

The CSS selector:

.foo

akan memilih elemen apapun yang memiliki kelas foo .

Bagaimana Anda melakukan ini di XPath?

Meskipun XPath lebih kuat dari CSS, XPath tidak memiliki native setara dengan pemilih kelas CSS . Namun, ada solusinya.

Cara yang tepat untuk melakukannya

Pemilih yang setara di XPath adalah:

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

Fungsi menormalkan strip spasi di depan dan di belakang spasi putih (dan juga menggantikan urutan karakter spasi putih dengan satu spasi).

(Dalam pengertian yang lebih umum) ini juga setara dengan pemilih CSS:

*[class~="foo"]

yang akan cocok dengan elemen apa pun yang nilai atribut kelasnya adalah daftar nilai yang dipisahkan spasi, salah satunya sama persis dengan foo .

Sepasang cara yang jelas, tetapi salah untuk melakukannya

Pemilih XPath:

//*[@class="foo"]

tidak bekerja! karena tidak akan cocok dengan elemen yang memiliki lebih dari satu kelas, misalnya

<div class="foo bar">

Itu juga tidak akan cocok jika ada spasi ekstra di sekitar nama kelas:

<div class="  foo ">

Pemilih XPath yang 'ditingkatkan'

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

tidak berhasil! karena salah mencocokkan elemen dengan kelas foobar , misalnya

<div class="foobar">

Penghargaan diberikan kepada kawan ini, yang merupakan solusi paling awal yang diterbitkan untuk masalah ini yang saya temukan di web: http://dubinko.info/blog/2007/10/01/simple-parsing-of-space-seprated-attributes- di-xpathxslt /

pengguna716736
sumber
Apa perlunya menormalkan-ruang?
Freek
"jawaban di atas" mungkin mengacu pada MrGlass's.
LarsH
Apakah ini mungkin <div class="foo\tbar">? Maksud saya, nama kelas dipisahkan oleh tab.
Frozen Flame
1
tetapi <div class = "group-condition" /> dan <div class = "condition" /> sama untuk $ x ('// div [contains (concat ("", normalize-space (@class)), " ")," condition ")] ')
Memke
1
@ testerjoe2 apakah Anda mencoba //*[contains(concat(" ", normalize-space(@class), " "), " foo ")]?
Niels Bom
11

//[@class="date"] bukan xpath yang valid.

Coba //*[@class="date"], atau jika Anda tahu itu adalah gambar,//img[@class="date"]

MrGlass
sumber
7

XPath 3.1 memperkenalkan fungsi berisi-token dan akhirnya menyelesaikan ini 'secara resmi'. Ini dirancang untuk mendukung kelas .

Contoh:

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

Fungsi ini memastikan bahwa spasi (tidak hanya (U + 0020)) ditangani dengan benar, berfungsi jika pengulangan nama kelas, dan umumnya mencakup kasus tepi.


Catatan: Mulai hari ini (2016-12-13) XPath 3.1 berstatus Rekomendasi Kandidat .

Robin Pokorny
sumber
Itu tidak berfungsi di chrome terbaru saat ini. Sampai berhasil, bagaimana kita mengatasi batasan bahwa // * [berisi (@class, "foo")] juga akan memilih semua kelas yang berisi foo, seperti foobar, fooz dll.
MasterJoe
1

HTML memungkinkan elemen tidak peka huruf besar dan nama atribut dan kemudian kelas adalah daftar nama kelas yang dipisahkan spasi. Di sini kita pergi untuk sebuah imgtag dan classbernama date:

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

Lihat juga: Konversi Pemilih CSS ke XPath

hakre
sumber
1

WASPADAI TANDA MINUS DI TEMPLATE !!! Jika Anda menanyakan "my-ownclass" di 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
sumber