Xpath ile bir css sınıfı seçme


87

Kendi başına .date adında bir sınıf seçmek istiyorum

Nedense bunu çalıştıramıyorum. Kodumda neyin yanlış olduğunu bilen biri varsa, çok memnun olur.

@$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
peki ya html parçası? (Bize asXML'den () gelen simpleXml çıktısını xpath'e yaklaştıkça göstermeyi tercih edin)
SergeS

birden fazla sınıf varsa yapmanız gerekencontains(@class, 'date')
Gordon


olası XPath
hakre

@ Gordon'un cevabı tehlikelidir, eğer sınıf niteliği "tarihsaat" ise bu da eşleşecektir. user716736'nın yanıtı daha eksiksiz.
Niels Bom

Yanıtlar:


242

Bu soruya kanonik cevabı yazmak istiyorum çünkü yukarıdaki cevabın bir problemi var.

Bizim problemimiz

CSS seçici:

.foo

foo sınıfına sahip herhangi bir öğeyi seçecektir .

Bunu XPath'te nasıl yaparsınız?

XPath, CSS'den daha güçlü olmasına rağmen, XPath'in CSS sınıf seçicisinin yerel eşdeğeri yoktur . Ancak bir çözüm var.

Bunu yapmanın doğru yolu

XPath'deki eşdeğer seçici :

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

Normalize-space işlevi, beyaz boşluğun başındaki ve sonundaki boşlukları şeritler (ve ayrıca boşluk karakterleri dizilerini tek bir boşlukla değiştirir).

(Daha genel anlamda) bu aynı zamanda CSS seçicinin eşdeğeridir:

*[class~="foo"]

sınıf öznitelik değeri boşluklarla ayrılmış değerler listesi olan herhangi bir elemanla eşleşir , bunlardan biri foo'ya tam olarak eşittir .

Birkaç bariz, ancak bunu yapmanın yanlış yolları

XPath seçici:

//*[@class="foo"]

çalışmıyor! çünkü birden fazla sınıfa sahip bir öğeyle eşleşmez, örneğin

<div class="foo bar">

Sınıf adının çevresinde fazladan boşluk varsa da eşleşmez:

<div class="  foo ">

'Gelişmiş' XPath seçici

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

da çalışmıyor! çünkü öğeleri sınıf foobarıyla yanlış bir şekilde eşleştiriyor , örneğin

<div class="foobar">

Kredi, web'de bulduğum bu soruna en erken yayınlanan çözüm olan bu adama gidiyor: http://dubinko.info/blog/2007/10/01/simple-parsing-of-space-seprated-attributes- in-xpathxslt /


Normalize-uzaya ihtiyaç nedir?
Freek

"yukarıdaki cevap" muhtemelen MrGlass'a atıfta bulunmaktadır.
LarsH

Bu mümkün <div class="foo\tbar">mü? Yani, bir sekmeyle ayrılmış sınıf adları.
Frozen Flame

1
ancak <div class = "group-condition" /> ve <div class = "condition" /> $ x için aynıdır ('// div [içerir (concat ("", normalize-space (@class), " ")," koşul ")] ')
Memke

1
@ testerjoe2 denedin //*[contains(concat(" ", normalize-space(@class), " "), " foo ")]mi?
Niels Bom

11

//[@class="date"] geçerli bir xpath değil.

Deneyin //*[@class="date"]veya bunun bir resim olduğunu biliyorsanız,//img[@class="date"]


7

XPath 3.1 , belirteç içeren bir işlev sunar ve böylece sonunda bunu 'resmi olarak' çözer. Sınıfları desteklemek için tasarlanmıştır .

Misal:

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

Bu işlev, beyaz boşluğun (yalnızca (U + 0020) değil) doğru şekilde işlendiğinden, sınıf adı tekrarı durumunda çalıştığından ve genellikle uç durumları kapsadığından emin olur.


Not: Bugün itibariyle (2016-12-13) XPath 3.1, Aday Öneri statüsüne sahiptir .


Bugünün en son Chrome'unda çalışmıyor. Çalıştığını kadar nasıl biz de foo içeren herhangi bir sınıf, örneğin filanca gibi fooz vb seçecektir // * [içeriyor (@class, "foo")] sınırlama dolaşırsınız
MasterJoe


1

HTML, büyük / küçük harfe duyarlı olmayan öğe ve öznitelik adlarına izin verir ve ardından sınıf, sınıf adlarının boşlukla ayrılmış bir listesidir. İşte bir imgetiket ve classadı için gidiyoruz date:

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

Ayrıca bakınız: CSS Seçiciden XPath'e dönüştürme


1

ŞABLONDA EKSİ İŞARETLERİNE DİKKAT !!! DOM’da "kendi sınıfım" için sorguluyorsanız:

<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.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.