使用PHP DOMDocument

时间:2015-05-07 08:54:21

标签: php html xml dom

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

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

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

  • 如果我使用loadHTML加载代码,名称空间将被删除,但我需要它来保持
  • 如果我使用loadXML加载代码,我会收到很多错误,说明我没有加载有效的XML

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

代码段:

<?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

&GT;

2 个答案:

答案 0 :(得分:2)

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

  • 使用另一个接受HMTL代码中的命名空间的解析器。查看here以获取HTML解析器的详细列表。这可能是最有效的方法。
  • 如果你想坚持使用DOMDocument,你基本上必须对代码进行预处理和后处理。

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

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

      然后会导致

      <fb:like xmlNamespace="fb" send="true" width="450" show_faces="true"></fb:like>
      
    • 现在将编辑后的代码提供给DOMDocument-&gt; loadHTML。它将删除命名空间,但它会保留导致

      的属性
      <like xmlNamespace="fb" send="true" width="450" show_faces="true"></like>
      
    • 现在(再次使用正则表达式,循环或任何你想要的)查找具有属性xmlNamespace的所有标记,并将该属性替换为实际的名称空间。别忘了将命名空间添加到结束标记中!

答案 1 :(得分:0)

基于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);

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