web-dev-qa-db-fra.com

Sélection d'une classe CSS avec xpath

Je veux juste choisir une classe appelée .date

Pour une raison quelconque, je ne peux pas que cela fonctionne. Si quelqu'un sait ce qui ne va pas avec mon code, ce serait très apprécié.

@$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." ";
}
78
Teddy13

Je veux écrire la réponse canonique à cette question parce que la réponse ci-dessus a un problème.

Notre problème

Le sélecteur [~ # ~] css [~ # ~] :

.foo

sélectionnera n'importe quel élément ayant la classe foo .

Comment faites-vous cela dans XPath?

Bien que XPath soit plus puissant que CSS, XPath n’a pas d’équivalent natif d’un sélecteur de classe CSS . Cependant, il existe une solution.

La bonne façon de le faire

Le sélecteur équivalent dans XPath est:

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

La fonction normaliser-espace supprime les espaces de début et de fin (et remplace également les séquences de caractères d'espacement par un seul espace).

(Dans un sens plus général), c'est aussi l'équivalent du sélecteur CSS:

*[class~="foo"]

qui correspond à tout élément dont la valeur d'attribut class class est une liste de valeurs séparées par des espaces, dont l'une est exactement égale à foo .

Quelques façons évidentes mais mauvaises de le faire

Le sélecteur XPath:

//*[@class="foo"]

ne fonctionne pas! parce qu'il ne correspondra pas à un élément ayant plus d'une classe, par exemple

<div class="foo bar">

Cela ne correspondra pas non plus s'il y a un espace supplémentaire autour du nom de la classe:

<div class="  foo ">

Le sélecteur XPath 'amélioré'

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

ne fonctionne pas non plus! car il associe à tort des éléments à la classe foobar , par exemple

<div class="foobar">

Le mérite en revient à cet homme, qui était la première solution publiée à ce problème que j'ai trouvée sur le Web: http://dubinko.info/blog/2007/10/01/simple-parsing-of-space- seprated-attributs-in-xpathxslt /

229
user716736

//[@class="date"] n'est pas un xpath valide.

Essayez //*[@class="date"], ou si vous savez que c'est une image, //img[@class="date"]

10
MrGlass

XPath 3.1 introduit une fonction contient-jeton et résout donc finalement ce "officiellement". Il est conçu pour classes de support .

Exemple:

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

Cette fonction garantit que l’espace blanc (pas seulement (U + 0020)) est gérée correctement, fonctionne en cas de répétition du nom de classe et couvre généralement les cas Edge.


Remarque: À compter d'aujourd'hui (2016-12-13), l'état de XPath 3.1 est Recommandation du candidat.

7
Robin Pokorny

Dans XPath 2.0, vous pouvez:

//*[count(index-of(tokenize(@class, '\s+' ), 'foo')) = 1]

comme indiqué par Christian Weiske dans: https://cweiske.de/tagebuch/XPath%3A%20Select%20element%20by%20class.htm

3
Memke

Le HTML autorise les noms d’attributs et d’éléments insensibles à la casse, puis class est une liste de noms de classes séparée par des espaces. Ici nous allons pour une balise img et le class nommé date:

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

Voir aussi: Conversion du sélecteur CSS en XPath

1
hakre

ATTENTION AUX SIGNES MOINS DANS LE MODÈLE !!! Si vous recherchez "my-ownclass" dans 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.
1
Vlado