Как избежать разбора DOM, добавив html doctype, теги <head>и <body>? - PullRequest
7 голосов
/ 07 октября 2009
<?
    $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.

Ответы [ 6 ]

7 голосов
/ 07 октября 2009

Я на самом деле ищу такое же решение. Для этого я использовал метод 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% без изменений, но оно близко.

4 голосов
/ 02 ноября 2018

Эй, почему бы не ответить на 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>.

3 голосов
/ 02 марта 2011

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

Редактировать: Мех, неважно. Мне нравится решение медера.

1 голос
/ 07 октября 2009

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

echo preg_replace("/<!DOCTYPE [^>]+>/", "", $dom->saveHTML());
0 голосов
/ 07 мая 2015

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

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

У меня работает.

0 голосов
/ 07 октября 2009

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

Также, вместо saveHTML(), вы можете попробовать saveXML()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...