使用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呢?(更喜欢向我们展示asXML()的simpleXml输出,因为它更接近xpath)
SergeS 2012年

如果您需要多个课程contains(@class, 'date')
戈登



@Gordon的答案很危险,如果class属性是“ datetime”,它也会匹配。user716736的答案更加完整。
Niels Bom 2012年

Answers:


242

我想为这个问题写一个规范的答案,因为上面的答案有问题。

我们的问题

CSS选择器:

.foo

将选择具有foo类的任何元素。

您如何在XPath中做到这一点?

尽管XPath比CSS强大,但是XPath没有CSS类选择器的本地等效项。但是,有一个解决方案。

正确的做法

XPath中的等效选择器是:

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

函数归一化空间,以去除开头和结尾的空白(并且还将空格字符序列替换为单个空格)。

(从更一般的意义上讲)这也等同于CSS选择器:

*[class~="foo"]

它将匹配其属性值是由空格分隔的值的列表的任何元素,其中一个值等于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 2015年

这可能<div class="foo\tbar">吗?我的意思是,类名用制表符分隔。
冷冻火焰

1
但是<div class =“ group-conditions” />和<div class =“ condition” />对于$ x('// div [contains(concat(“”,normalize-space(@class),“ “),” condition“)]')
Memke '16

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的状态为候选推荐


它不适用于当今最新的Chrome。直到它起作用,我们如何绕过// * [contains(@class,“ foo”)]也将选择任何包含foo的类的限制,例如foobar,fooz等
。– MasterJoe

3

在XPath 2.0中,您可以:

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

如Christian Weiske在以下网址中所述:https ://cweiske.de/tagebuch/XPath%3A%20Select%20element%20by%20class.htm


不幸的是,截至2017年6月12日,chrome似乎尚未实现此功能。根据en.wikipedia.org/wiki/…似乎缺乏全面的信息
JonnyRaa

1

HTML允许不区分大小写的元素和属性名称,然后class是由空格分隔的类名称列表。在这里,我们寻找一个img标签和class名为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.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.