2016-09-13 50 views
1

为什么会变成这样的代码:PHP的DOMDocument saveHTML打破格式

$doc = new DOMDocument(); 
$doc->loadHTML($this->content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 
$imgNodes = $doc->getElementsByTagName('img'); 

if ($imgNodes->length > 0) { 
    $inlineImage = new Image(); 
    $inlineImage->setPublicDir($publicDirPath); 

    foreach ($imgNodes as $imgNode) { 
     $inlineImage->setUri($imgNode->getAttribute('src')); 
     $inlineImage->setName(basename($inlineImage->getUri())); 

     if ($inlineImage->getUri() != $dstPath.$inlineImage->getName()) { 
      $inlineImage->move($dstPath); 

      $imgNode->setAttribute('src', $dstPath.'/'.$inlineImage->getName());     
     } 
    } 

    $this->content = $doc->saveHtml(); 

} 

这个代码执行:

<p><img alt="fluid cat" src="/images/tmp/fluid-cat.jpg"></p><p><img alt="pandas" src="/images/tmp/pandas.jpg"></p> 

结果在此代码:

<p><img alt="fluid cat" src="/images/full/2016-09/fluid-cat.jpg"><p><img alt="pandas" src="/images/full/2016-09/pandas.jpg"></p></p> 

为什么它把两个IMG第一个p块内的标签?

+0

因为您的html示例没有根元素。 Libxml假定第一个p是根元素并执行自动修复。它删除了“孤儿”关闭p标签,并将结束标签放在“好地方”,即最后。为了解决这个问题,添加一个伪造的根元素(例如'

....
'或者删除'LIBXML_HTML_NOIMPLIED')并且一个接一个地提取它的子节点以通过串联创建结果字符串。 –

+0

我很确定DomDocument试图正确地格式化HTML的东西。尝试在img标签的末尾添加一个'/',以使其自动关闭 – bassxzero

+0

'loadHTML()'和'saveHTML()'在实践中是非常破碎和无用的。考虑使用像[html5lib-php](https://github.com/html5lib/html5lib-php)和自定义HTML代码生成器这样的第三方HTML解析器。 –

回答

4

您的html示例没有围绕所有的根元素。当LIBXML分析html来构建DOM树时,它假定遇到的第一个标记是根元素。结果,第一个标签</p>被视为孤儿关闭标签(因为后面有内容)并自动删除,并在末尾添加</p>以关闭根元素。

为了避免在使用html部件(而不是整个html文档)时进行这些自动修复,您需要添加一个假根元素。最后,为了产生结果字符串,你需要保存这个假根元素的每个子节点。例如:

$html = '<p><img alt="fluid cat" src="/images/tmp/fluid-cat.jpg"></p><p><img alt="pandas" src="/images/tmp/pandas.jpg"></p>'; 

$doc = new DOMDocument; 
$doc->loadHTML('<div>' . $html . '</div>', LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED); 
#    ^-----------------^----- fake root element 
$root = $doc->documentElement; 

$result = ''; 

foreach($root->childNodes as $childNode) { 
    $result .= $doc->saveHTML($childNode); 
} 

echo $result;