xpathを使用したCSSクラスの選択


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の断片はどうですか?(xPathに近いため、asXML()からのsimpleXml出力を表示することをお勧めします)
SergeS 2012年

複数のクラスが必要な場合contains(@class, 'date')
Gordon



@Gordonの回答は危険です。class属性が「datetime」の場合も一致します。user716736の答えはより完全です。
Niels Bom

回答:


242

上記の回答には問題があるため、この質問に対する正規の回答を書きたいと思います。

私たちの問題

CSSのセレクタ:

.foo

クラスfooを持つ要素を選択します。

XPathでこれをどのように行いますか?

XPathはCSSよりも強力ですが、XPathにはCSSクラスセレクターに相当するネイティブな機能はありません。ただし、解決策があります。

それを行う正しい方法

XPathでの同等のセレクターは次のとおりです。

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

関数normalize-spaceは、先頭と末尾の空白を取り除きます(また、空白文字のシーケンスを単一の空白で置き換えます)。

(より一般的な意味で)これはCSSセレクターと同等です。

*[class~="foo"]

これは、クラス属性値が空白で区切られた値のリストであるすべての要素に一致します。値の1つはfooとまったく同じです。

いくつかの明白だが間違った方法

XPathセレクター:

//*[@class="foo"]

動作しません!たとえば、複数のクラスを持つ要素とは一致しないためです。

<div class="foo bar">

また、クラス名の前後に余分な空白がある場合も一致しません。

<div class="  foo ">

「改良された」XPathセレクター

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

どちらも機能しません!たとえば、要素がfoob​​arクラスの要素と誤って一致するためです。

<div class="foobar">

クレジットは、私がウェブで見つけたこの問題の最も早い公開された解決策であるこのフェラに行きます:http : //dubinko.info/blog/2007/10/01/simple-parsing-of-space-seprated-attributes- in-xpathxslt /


スペースを正規化する必要性は何ですか?
Freek 2014年

「上記の答え」はおそらくMrGlassのものを指します。
LarsH

これは可能<div class="foo\tbar">ですか?つまり、タブで区切られたクラス名。
Frozen Flame

1
ただし、<div class = "group-conditions" />および<div class = "condition" />は、$ x( '// div [contains(concat( ""、normalize-space(@class)、 " ")、" condition ")] ')
Memke

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)だけでなく)空白が正しく処理され、クラス名が繰り返された場合に機能し、通常はエッジケースがカバーされます。


注:本日(2016-12-13)現在、XPath 3.1はCandidate Recommendationのステータスになっています。


今日の最新のクロムでは動作しません。それが機能するまで、// * [contains(@class、 "foo")]がfoobar、foozなどのfooを含むクラスも選択するという制限を回避するにはどうすればよいですか
MasterJoe


1

HTMLでは、大文字と小文字を区別しない要素名と属性名を使用でき、クラスはスペースで区切られたクラス名のリストです。ここでは、imgタグとclassnamedを使用しdateます。

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

参照:CSSセレクターからXPathへの変換


1

テンプレートのマイナス記号に注意してください!!! DOMで「my-ownclass」を照会している場合:

<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.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.