使用 xpath 选择 css 类

Posted

技术标签:

【中文标题】使用 xpath 选择 css 类【英文标题】:Selecting a css class with xpath 【发布时间】:2012-02-07 04:45:05 【问题描述】:

我只想选择一个名为 .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." ";

【问题讨论】:

那段 html 呢? (更喜欢向我们展示 asXML() 的 simpleXml 输出,因为它更接近 xpath) 如果有多个类你需要做contains(@class, 'date') php - Parse All Links That Contain A Speciffic Word In "href" Tag的可能重复 XPath: How to match attributes that contain a certain string的可能重复 @Gordon 的回答很危险,如果类属性是“datetime”,它也会匹配。 user716736的回答比较完整。 【参考方案1】:

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

我们的问题

CSS 选择器:

.foo

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

如何在 XPath 中做到这一点?

虽然 XPath 比 CSS 更强大,但 XPath 没有 CSS 类选择器的原生等效项。但是,有一个解决方案。

正确的做法

XPath 中的等效选择器是:

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

函数normalize-space 去除前导和尾随空格(并且还将空白字符序列替换为单个空格)。

(在更一般的意义上)这也相当于 CSS 选择器:

*[class~="foo"]

将匹配任何 class 属性值为空格分隔值列表的元素,其中一个值与 foo 完全相同。

一些明显但错误的方法

XPath 选择器:

//*[@class="foo"]

不起作用!因为它不会匹配具有多个类的元素,例如

<div class="foo bar">

如果类名周围有多余的空格,它也不会匹配:

<div class="  foo ">

“改进的”XPath 选择器

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

也不行!因为它错误地将元素与 foobar 类匹配,例如

<div class="foobar">

感谢这个家伙,他是我在网上找到的最早发布的解决此问题的方法: http://dubinko.info/blog/2007/10/01/simple-parsing-of-space-seprated-attributes-in-xpathxslt/

【讨论】:

规范化空间需要什么? “上面的答案”可能是指 MrGlass 的。 这可能吗&lt;div class="foo\tbar"&gt;?我的意思是,用制表符分隔的类名。 但 和 对于 $x('//div[contains(concat(" ", normalize -space(@class), " "), "条件")]') @testerjoe2 你试过//*[contains(concat(" ", normalize-space(@class), " "), " foo ")] 吗?【参考方案2】:

XPath 3.1 引入了一个函数contains-token,因此最终“正式”解决了这个问题。专为support classes设计。

示例:

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

此函数确保正确处理空白(不仅是 (U+0020)),在类名重复的情况下工作,并且通常涵盖边缘情况。


注意:截至今天 (2016-12-13) XPath 3.1 的状态为候选推荐

【讨论】:

它在今天最新的 chrome 中不起作用。在它起作用之前,我们如何绕过 //*[contains(@class, "foo")] 也会选择任何包含 foo 的类的限制,例如 foobar、fooz 等。【参考方案3】:

在 XPath 2.0 中,您可以:

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

正如克里斯蒂安·韦斯克所说: https://cweiske.de/tagebuch/XPath%3A%20Select%20element%20by%20class.htm

【讨论】:

不幸的是,截至 2017 年 6 月 12 日,chrome 似乎并未实现此功能。基于en.wikipedia.org/wiki/…,它似乎全面缺乏【参考方案4】:

当心模板中的减号!如果您在 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.

【讨论】:

【参考方案5】:

HTML 允许不区分大小写的元素和属性名称,然后 class 是一个空格分隔的类名列表。在这里,我们使用 img 标签和名为 dateclass

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

另请参阅:CSS Selector to XPath conversion

【讨论】:

【参考方案6】:

//[@class="date"] 不是有效的 xpath。

试试//*[@class="date"],或者如果你知道这是一张图片,//img[@class="date"]

【讨论】:

以上是关于使用 xpath 选择 css 类的主要内容,如果未能解决你的问题,请参考以下文章

使用 CSS 或 XPath 选择器解析 HTML?

CSS / XPATH 选择器查询

如何在 Chrome 开发者工具中使用 XPath 或 CSS 选择器搜索 DOM 元素?

使用 xpath 或 css 选择器解析混合移动应用程序中的所有元素

10 xpath定位元素

(CSS / jQuery/ XPath) 用于从姐妹/兄弟节点 (DOM) 获取内部文本的选择器