使用 PHP DOMDocument 解析脏 html 代码时遇到困难

Posted

技术标签:

【中文标题】使用 PHP DOMDocument 解析脏 html 代码时遇到困难【英文标题】:Having difficulties parsing dirty html code with PHP DOMDocument 【发布时间】:2015-07-17 17:51:12 【问题描述】:

我希望能够加载任何 html 文档并使用 php 的 domdocument 功能对其进行编辑。 问题是,一些网站,例如 facebook,将 XML 样式的命名空间添加到它们的标签中。

<fb:like send="true"  show_faces="true"></fb:like>

DOMDocument 对脏代码非常宽容,但它不接受 html 代码中的命名空间。会发生什么:

如果我使用 loadHTML 加载代码,命名空间将被剥离,但我需要保留它 如果我使用 loadXML 加载代码,我会收到大量错误,指出我没有加载有效的 XML

所以我的想法是将获得的 html 转换为 XML,以便我可以使用 loadXML 解析它。我的问题是,我该怎么做,我应该使用哪个工具(我听说过 Tidy,但我无法让它工作)还是使用不同的解析器更好(一个可以处理 html 中的命名空间的解析器代码)

代码sn-p:

<?php
$html = file_get_contents($_POST['url']);

$domDoc = new DOMDocument();
$domDoc->loadHTML($html);

//Just do anything here. It doesn't matter what. For example I'm deleting the head tag
$headTag = $domDoc->getElementsByTagName("head")->item(0);
$headTagParent = $headTag->parentNode;
$headTagParent->removeChild($headTag);

echo $domDoc->saveHTML();

//This will work as expected for any url EXCEPT the ones that use XML namespaces like facebook does as described above. In case of such dirty coding the namespace will get deleted by DOMDocument

?>

【问题讨论】:

Convert HTML code to doc using PHP and PHPWord 的可能重复项 请编辑您的问题并添加您的 HTML/XML 的最小示例。 @Varun Naharia 很抱歉,但这对我毫无帮助。那不是我的问题的答案。 @michi 我真的认为这里不需要代码示例。我只想能够将任何 HTML 代码转换为 XML。随便,没什么特别的。 您没有将 html 转换为 doc 吗? 【参考方案1】:

在 Syndace 的回答的基础上,这里有一些基于正则表达式的代码,这些代码将通过将每个冒号替换为“___”来转义您的命名空间(您可以选择其他一些您认为更安全的转义序列):

$modifiedHtml = preg_replace('/<(\/?)([a-z]+)\:/', '<$1$2___', $inputHtml);
$x = $doc->loadHTML($modifiedHtml);
// ...if desired, do stuff to your parsed html here...
$outputHtml = preg_replace('/<(\/?)([a-z]+)___/', '<$1$2:', $doc->saveHtml);

这应该适用于&lt;fb:like&gt;&lt;mynamespace:mytag&gt; 或您扔给它的任何其他东西。

【讨论】:

【参考方案2】:

没有一种干净的方法可以使用 DOMDocument 解析带有命名空间的 HTML 而不会丢失命名空间,但是有一些解决方法:

使用另一个在 HMTL 代码中接受命名空间的解析器。查看here 以获得一份漂亮而详细的 HTML 解析器列表。这可能是最有效的方法。

如果您想坚持使用 DOMDocument,您基本上必须对代码进行预处理和后处理。

在将代码发送到 DOMDocument->loadHTML 之前,请使用正则表达式、循环或任何您想查找所有命名空间标签的方式,并将自定义属性添加到包含命名空间的开始标签。

<fb:like send="true"  show_faces="true"></fb:like>

然后会导致

<fb:like xmlNamespace="fb" send="true"  show_faces="true"></fb:like>

现在将编辑后的代码提供给 DOMDocument->loadHTML。它会去除命名空间,但会保留导致的属性

<like xmlNamespace="fb" send="true"  show_faces="true"></like>

现在(再次使用正则表达式、循环或任何你想要的)找到所有带有属性 xmlNamespace 的标签,并用实际的命名空间替换该属性。不要忘记将命名空间也添加到结束标记中!

【讨论】:

以上是关于使用 PHP DOMDocument 解析脏 html 代码时遇到困难的主要内容,如果未能解决你的问题,请参考以下文章

这是 PHP 的 DOMDocument 库中的错误吗?

PHP DOMDocument 的类 jQuery 选择器

PHP DOMDocument 添加了额外的标签

来自DOMDocument的nodeValue在PHP中返回奇怪的字符

html5-tags 上的 PHP DOMDocument 错误/警告

DOMDocument::loadHTML(): 由于输入错误,输入转换失败