用户将提供HTML,它可能是有效的,也可能是无效的(格式错误)。我需要能够确定以下内容:
- 正文中有样式标签吗
- 是否有一个div具有使用宽度或背景图像的style属性
我尝试过使用DOMDocument类,但它只能使用xPath执行1而不能执行2。
我也尝试过simple_html_dom,它只能做1而不能做2。
你认为我只使用正则表达式是个好主意吗?还是有什么我没有想到的?
Regex是NEVER(再次:NEVER!)解析HTML的解决方案!
Regex可用于第3类乔姆斯基语言(常规语言)
然而,HTML是一种类型2的乔姆斯基语言(上下文无关语言)。
如果仍有疑问:http://en.wikipedia.org/wiki/Chomsky_hierarchy#The_hierarchy
为了安全地使用类型2语言,您需要一个上下文无关的语言解析器。您可能想要尝试LL解析器或递归下降解析器,例如
话虽如此:
将body
与style
:匹配
<body's+[^>]*style's*='s*["'].*?[^"']*?["'][^>]*>
在style
:中匹配div
和width|background-image
<div's+[^>]*style's*='s*["'][^"']*?(width|background-image)[^"']*?["'][^>]*>
它们都错误地匹配所说的标签,如果被注释掉(这就是为什么我说不可能)。
XPath可以同时执行(1)和(2):
测试正文中是否有样式标签:
//body//style
使用width
或background-image
:测试是否存在具有样式属性的div
//div[contains(@style,'width:') or contains(@style,'background-image:')]
而且,正如您在评论中所好奇的那样,查看样式标签是否包含a:hover
或font-size
:
//style[contains(text(),'a:hover') or contains(text(),'font-size:')]
您可以使用Tidy清理HTML,然后将其解析为XML。然后可以很容易地使用xpath来查找节点。试试这样的东西:
$tidyConfig = array(
"add-xml-decl" => true,
"output-xml" => true,
"numeric-entities" => true
);
$tidy = new tidy();
$tidy->parseString($html, $tidyConfig, "utf8");
$tidy->cleanRepair();
$xml = new SimpleXMLElement($tidy);
$matches = $xml->xpath('style');
至于解析样式属性以查找特定的选择器,我认为您必须手动进行。如果您愿意,可以使用CSS解析器。
用正则表达式解析HTML是一个好主意。然而,任何优秀的HTML解析器都能够找到所有带有style
标记的div
,一旦完成了这些操作,regex就可以用于解析样式属性。
然而,复杂(但有效)的CSS仍然有可能破坏大多数正则表达式,因此真正持久的东西是HTML解析器与CSS解析器相结合。不过,这可能有些过头了;像'bwidth's*:'s*('w+)
这样的正则表达式很可能会捕获任何width
值,除非有人试图欺骗它
编辑:
一个好的HTML解析器不会阻塞任何不会阻塞浏览器的东西。我不再是一个PHP爱好者,但我听说了一些关于HTML净化器的好消息。