我想自己选择一个名为 .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." ";
}
contains(@class, 'date')
我想写这个问题的规范答案,因为上面的答案有问题。
我们的问题
CSS 选择器:
.foo
将选择任何具有类 foo 的元素。
你如何在 XPath 中做到这一点?
尽管 XPath 比 CSS 更强大,但 XPath 没有与 CSS 类选择器等效的本机。但是,有一个解决方案。
正确的方法
XPath 中的等效选择器是:
//*[contains(concat(" ", normalize-space(@class), " "), " foo ")]
函数 normalize-space 去除前导和尾随空白(并且还用单个空格替换空白字符序列)。
(在更一般的意义上)这也相当于 CSS 选择器:
*[class~="foo"]
它将匹配任何其类属性值为空格分隔值列表的元素,其中一个值完全等于 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/
//[@class="date"]
不是有效的 xpath。
试试 //*[@class="date"]
,或者如果您知道它是图像,//img[@class="date"]
XPath 3.1 引入了一个函数 contains-token,因此最终“正式”解决了这个问题。它被设计为support classes。
例子:
//*[contains-token(@class, "foo")]
此函数确保正确处理空白(不仅是 (U+0020)),在类名重复的情况下工作,并且通常涵盖边缘情况。
注意:截至今天 (2016-12-13) XPath 3.1 的状态为候选推荐。
在 XPath 2.0 中,您可以:
//*[count(index-of(tokenize(@class, '\s+' ), 'foo')) = 1]
正如 Christian Weiske 在:https://cweiske.de/tagebuch/XPath%3A%20Select%20element%20by%20class.htm
HTML 允许不区分大小写的元素和属性名称,然后 class 是一个空格分隔的类名列表。我们在这里找到一个 img
标记和名为 date
的 class
:
//*['IMG' = translate(name(.), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')]/@*['CLASS' = translate(name(.), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') and contains(concat(' ', normalize-space(.), ' '), concat(' ', 'date', ' '))]
另请参阅:CSS Selector to XPath conversion
当心模板中的减号!如果您在 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.
不定期副业成功案例分享
<div class="foo\tbar">
吗?我的意思是,用制表符分隔的类名。//*[contains(concat(" ", normalize-space(@class), " "), " foo ")]
吗?