如何避免DOM解析添加html doctype和标签?

时间:2009-10-06 21:25:25

标签: php parsing dom

<?
    $string = '
    Some photos<br>
    <span class="naslov_slike">photo_by_ile_IMG_1676-01</span><br />
    <span class="naslov_slike">photo_by_ile_IMG_1699-01</span><br />
    <span class="naslov_slike">photo_by_ile_IMG_1697-01</span><br />
    <span class="naslov_slike">photo_by_ile_IMG_1695-01</span><br />    
    ';

    $dom = new DOMDocument();
    $dom->loadHTML($string);
    $dom->preserveWhiteSpace = false;
    $elements = $dom->getElementsByTagName('span');
    $spans = array();
    foreach($elements as $span) {
        $spans[] = $span;
    }
    foreach($spans as $span) {
        $span->parentNode->removeChild($span);
    }
    echo $dom->saveHTML();


?>

我正在使用此代码来解析字符串。当此函数返回string时,它有一些添加的标记:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>Some photos<br><br><br><br><br></p></body></html>

有没有办法避免这种情况并且返回干净的字符串?这个输入字符串就是例如,在使用中它可以是任何html字符串。

6 个答案:

答案 0 :(得分:7)

我实际上在寻找相同的解决方案。我一直在使用innerHTML方法来执行此操作,但是当您执行loadHTML时,仍然会添加文本节点周围的<p>。我没有办法绕过它而不使用另一个解析器,或者有一些隐藏的标志告诉它不要那样做。

此代码:

<?php

function innerHTML($node){
  $doc = new DOMDocument();
  foreach ($node->childNodes as $child)
    $doc->appendChild($doc->importNode($child, true));

  return $doc->saveHTML();
}

 $string = '
    Some photos<br>
    <span class="naslov_slike">photo_by_ile_IMG_1676-01</span><br />
    <span class="naslov_slike">photo_by_ile_IMG_1699-01</span><br />
    <span class="naslov_slike">photo_by_ile_IMG_1697-01</span><br />
    <span class="naslov_slike">photo_by_ile_IMG_1695-01</span><br />    
    ';

    $dom = new DOMDocument();
    $dom->preserveWhiteSpace = false;
    $dom->loadHTML($string);
    $elements = $dom->getElementsByTagName('span');
    $spans = array();
    foreach($elements as $span) {
        $spans[] = $span;
    }
    foreach($spans as $span) {
        $span->parentNode->removeChild($span);
    }

    echo innerHTML( $dom->documentElement->firstChild );

将输出:

<p>Some photos<br><br><br><br><br></p>

然而,当然这个解决方案并没有保持100%完整的标记,但它已经接近了。

答案 1 :(得分:4)

为什么不回答一个9岁的问题? PHP 5.4版本(在提出此问题3年后发布)向options添加了DomDocument::loadHTML()参数。有了它,您可以执行以下操作:

$dom = new DomDocument();
$dom->loadHTML($string, LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED);
// do stuff
echo $dom->saveHTML();

我们传递两个常量:LIBXML_HTML_NODEFDTD表示不添加文档类型定义,而LIBXML_HTML_NOIMPLIED表示不添加隐含元素,例如<html><body>

答案 2 :(得分:3)

使用loadHTML后,您可以这样做:

# loadHTML causes a !DOCTYPE tag to be added, so remove it:
$dom->removeChild($dom->firstChild);

# it also wraps the code in <html><body></body></html>, so remove that:
$dom->replaceChild($dom->firstChild->firstChild->firstChild, $dom->firstChild);

!DOCTYPE标记将被删除,body标记内的第一个标记将替换html标记。

显然,只有当你对body中的第一个标签感兴趣时才会这样做,就像我遇到这个问题时一样。但是这个例子可以用来复制body内的所有内容,只需要一点努力。

编辑:嗯,没关系。我喜欢meder的解决方案。

答案 3 :(得分:1)

你总是可以使用正则表达式去除第一位:

echo preg_replace("/<!DOCTYPE [^>]+>/", "", $dom->saveHTML());

答案 4 :(得分:0)

从手册中: http://php.net/manual/en/domdocument.savehtml.php

$html_fragment = preg_replace('/^<!DOCTYPE.+?>/', '', str_replace( array('<html>', '</html>', '<body>', '</body>'), array('', '', '', ''), $dom->saveHTML()));

适合我。

答案 5 :(得分:-2)

我不确定其中任何一个是否真的有用,但您可以在构建DOMDocument时尝试使用DOMImplementation::createDocument - 第三个参数是您希望使用的DOCTYPE

此外,您可以尝试saveXML()

,而不是saveHTML()