Как избежать синтаксического анализа DOM, добавляя HTML doctype и теги?

<?
    $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();


?>

Я использую этот код для разбора строки. Когда строка возвращается этой функцией, она имеет некоторые добавленные теги:

<!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.

5 ответов


Я на самом деле ищу то же самое решение. Я использую метод innerHTML для этого, однако <p> вокруг текстового узла все равно будет добавлен, когда вы сделаете loadHTML. Я не могу обойти это без использования другого парсера, или есть какой-то скрытый флаг, чтобы сказать ему не делать этого.

этот код:

<?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% неповрежденной, но это закрывать.


после использования 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 С небольшим усилием.

Edit: Meh, nevermind. Мне нравится Медера решение.


вы всегда можете просто использовать регулярное выражение, чтобы удалить этот первый бит:

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

из руководства: http://php.net/manual/en/domdocument.savehtml.php

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

работает для меня.


Я не уверен, что любой из них будет работать, но вы можете попробовать использовать DOMImplementation::createDocument при создании DOMDocument - третий аргумент -DOCTYPE вы хотите использовать.

кроме того, вместо saveHTML(), вы могли бы попробовать saveXML()