Penggunaan fungsi GETELEMENTBYTAG pada PHP

Sekalian saya upload juga karya Ibnu Daqiqil Ied, M.Ti. tentang Mengenal dan mamahami Codeigniter 2. sangat disarankan sebelum membaca ebook ini, anda harus memahami dulu OOP di PHP, sebab CI (singkatan dari Codeigniter) menggunakan sistem pemrograman modular, yang itu adanya di OOP PHP. Jangan berkecil hati. Orang lain menciptakan, kita hanya mempelajari dan memahami. Pasti bisa!. Semangat Coding...!

Saya fungsi di bawah ini, saya berjuang untuk menampilkan DOMDocument tanpa menambahkan XML, HTML, body dan p tag sebelum pembungkus konten. Perbaikan yang disarankan:

$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));

Hanya berfungsi ketika konten tidak memiliki elemen level blok di dalamnya. Namun, ketika itu terjadi, seperti pada contoh di bawah ini dengan elemen h2, output yang dihasilkan dari saveXML dipotong ke ...

Jika Anda suka

Saya telah menunjuk posting ini sebagai solusi yang mungkin, tetapi saya tidak dapat memahami bagaimana mengimplementasikannya ke dalam solusi ini (lihat upaya yang dikomentari di bawah).

Ada saran?

function rseo_decorate_keyword($postarray) {
    global $post;
    $keyword = "Jasmine Tea"
    $content = "If you like 

jasmine tea

you will really like it with Jasmine Tea flavors. This is the last ocurrence of the phrase jasmine tea within the content. If there are other instances of the keyword jasmine tea within the text what happens to jasmine tea." $d = new DOMDocument(); @$d->loadHTML($content); $x = new DOMXpath($d); $count = $x->evaluate("count(//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and (ancestor::b or ancestor::strong)])"); if ($count > 0) return $postarray; $nodes = $x->query("//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and not(ancestor::h2) and not(ancestor::h2) and not(ancestor::h3) and not(ancestor::h4) and not(ancestor::h5) and not(ancestor::h6) and not(ancestor::b) and not(ancestor::strong)]"); if ($nodes && $nodes->length) { $node = $nodes->item(0); // Split just before the keyword $keynode = $node->splitText(strpos($node->textContent, $keyword)); // Split after the keyword $node->nextSibling->splitText(strlen($keyword)); // Replace keyword with keyword $replacement = $d->createElement('strong', $keynode->textContent); $keynode->parentNode->replaceChild($replacement, $keynode); } $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0)); // $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->item(1)); // $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->childNodes); return $postarray; }

Semua jawaban ini sekarang salah, karena pada PHP 5.4 dan Libxml 2.6 loadHTML sekarang memiliki parameter $option yang memerintahkan Libxml tentang bagaimana seharusnya mem-parsing konten.

Karenanya, jika kita memuat HTML dengan opsi ini

$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

ketika melakukan saveHTML() tidak akan ada doctype, tidak ada , dan tidak ada .

LIBXML_HTML_NOIMPLIED mematikan penambahan otomatis elemen html/tubuh yang tersirat LIBXML_HTML_NODEFDTD mencegah doctype default ditambahkan ketika tidak ditemukan.

Dokumentasi lengkap tentang parameter Libxml adalah di sini

(Perhatikan bahwa dokumen loadHTML mengatakan bahwa Libxml 2.6 diperlukan, tetapi LIBXML_HTML_NODEFDTD hanya tersedia di Libxml 2.7.8 dan LIBXML_HTML_NOIMPLIED tersedia di Libxml 2.7.7)

Hapus saja node secara langsung setelah memuat dokumen dengan loadHTML (): 

# remove removeChild($doc->doctype);           

# remove  
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);

Gunakan saveXML() sebagai gantinya, dan kirimkan documentElement sebagai argumen untuk itu.

$innerHTML = '';
foreach ($document->getElementsByTagName('p')->item(0)->childNodes as $child) {
    $innerHTML .= $document->saveXML($child);
}
echo $innerHTML;

http://php.net/domdocument.savexml

Trik yang rapi adalah dengan menggunakan loadXML dan kemudian saveHTML . Tag html dan body dimasukkan pada tahap load, bukan pada tahap save.

$dom = new DOMDocument;
$dom->loadXML('

My DOMDocument contents are here

'); echo $dom->saveHTML();

NB bahwa ini sedikit hacky dan Anda harus menggunakan jawaban Jonah jika Anda bisa membuatnya bekerja.

gunakan DOMDocumentFragment

$html = 'what you want';
$doc = new DomDocument();
$fragment = $doc->createDocumentFragment();
$fragment->appendXML($html);
$doc->appendChild($fragment);
echo $doc->saveHTML();

Saya agak terlambat di klub tetapi tidak ingin tidak berbagi metode yang saya ketahui. Pertama-tama saya mendapatkan versi yang tepat untuk loadHTML () untuk menerima opsi-opsi bagus ini, tetapi LIBXML_HTML_NOIMPLIED tidak berfungsi pada sistem saya. Pengguna juga melaporkan masalah dengan parser (misalnya sini dan sini ).

Solusi yang saya buat sebenarnya cukup sederhana.

HTML yang akan dimuat dimasukkan ke dalam elemen

sehingga memiliki wadah berisi semua node untuk dimuat.

Kemudian elemen kontainer ini dihapus dari dokumen (tetapi DOMElement masih ada).

Kemudian semua anak langsung dari dokumen dihapus. Ini termasuk setiap tag , dan yang ditambahkan (secara efektif opsi LIBXML_HTML_NOIMPLIED) serta deklarasi (efektif LIBXML_HTML_NODEFDTD).

Kemudian semua anak langsung dari wadah ditambahkan ke dokumen lagi dan itu bisa menjadi output.

$str = '

Lorem ipsum dolor sit amet.

Nunc vel vehicula ante.

'; $doc = new DOMDocument(); $doc->loadHTML("
$str
"); $container = $doc->getElementsByTagName('div')->item(0); $container = $container->parentNode->removeChild($container); while ($doc->firstChild) { $doc->removeChild($doc->firstChild); } while ($container->firstChild ) { $doc->appendChild($container->firstChild); } $htmlFragment = $doc->saveHTML();

XPath berfungsi seperti biasa, hanya berhati-hati karena ada beberapa elemen dokumen sekarang, jadi bukan simpul root tunggal:

$xpath = new DOMXPath($doc);
foreach ($xpath->query('/p') as $element)
{   #                   ^- note the single slash "/"
    # ... each of the two 

element


  • PHP 5.4.36-1 + deb.sury.org ~ tepat + 2 (cli) (dibangun: 21 Des 2014 20:28:53) 

Masalah dengan jawaban teratas adalah LIBXML_HTML_NOIMPLIED tidak stabil.

Itu dapat menyusun ulang elemen (terutama, memindahkan tag penutup elemen atas ke bagian bawah dokumen), menambahkan tag p acak, dan mungkin berbagai masalah lain [1] . Mungkin menghapus tag html dan body untuk Anda, tetapi dengan biaya perilaku yang tidak stabil. Dalam produksi, itu bendera merah. Pendeknya:

Jangan gunakan LIBXML_HTML_NOIMPLIED. Sebagai gantinya, gunakan substr.


Pikirkan tentang itu. Panjang dan ditetapkan dan di kedua ujung dokumen - ukurannya tidak pernah berubah, dan posisi mereka juga tidak. Ini memungkinkan kami menggunakan substr untuk memotongnya:

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

echo substr($dom->saveHTML(), 12, -15); // the star of this operation

(INI IS BUKANLAH SOLUSI AKHIRNYA! Lihat di bawah untuk jawaban lengkap, teruslah membaca untuk konteksnya)

Kami memotong 12 dari awal dokumen karena = 12 karakter (<<>>+html+body = 4 + 4 + 4), dan kami mundur dan memotong 15 karena \n = 15 karakter (\n+//+<<>>+body+html = 1 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + + 4)

Perhatikan bahwa saya masih menggunakan LIBXML_HTML_NODEFDTD mengabaikan !DOCTYPE agar tidak disertakan. Pertama, ini menyederhanakan penghapusan tag HTML/BODY substr. Kedua, kami tidak menghapus doctype dengan substr karena kami tidak tahu apakah ' default doctype ' akan selalu menjadi sesuatu yang panjangnya tetap. Tapi, yang paling penting, LIBXML_HTML_NODEFDTD menghentikan parser DOM dari menerapkan doctype non-HTML5 ke dokumen - yang setidaknya mencegah parser dari memperlakukan elemen yang tidak dikenali sebagai teks longgar.

Kami tahu pasti bahwa tag HTML/BODY memiliki panjang dan posisi yang tetap, dan kami tahu bahwa konstanta seperti LIBXML_HTML_NODEFDTD tidak pernah dihapus tanpa semacam pemberitahuan penghentian, sehingga metode di atas akan bergulir dengan baik ke masa depan, TETAPI ...


... satu-satunya peringatan adalah bahwa implementasi DOM bisa mengubah cara tag HTML/BODY ditempatkan dalam dokumen - misalnya, menghapus baris baru di akhir dokumen, menambahkan spasi di antara tag , atau menambahkan baris baru.

Ini dapat diatasi dengan mencari posisi tag pembuka dan penutup untuk body, dan menggunakan offset itu untuk memangkas panjang kita. Kami menggunakan strpos dan strrpos untuk mencari offset dari depan dan belakang, masing-masing:

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

$trim_off_front = strpos($dom->saveHTML(),'') + 6;
// PositionOf + 6 = Cutoff offset after ''
// 6 = Length of ''

$trim_off_end = (strrpos($dom->saveHTML(),'')) - strlen($dom->saveHTML());
// ^ PositionOf - LengthOfDocument = Relative-negative cutoff offset before ''

echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);

Sebagai penutup, pengulangan jawaban final, bukti masa depan:

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

$trim_off_front = strpos($dom->saveHTML(),'') + 6;
$trim_off_end = (strrpos($dom->saveHTML(),'')) - strlen($dom->saveHTML());

echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);

Tidak ada DOCTYPE, tidak ada tag html, tidak ada tag tubuh. Kami hanya bisa berharap parser DOM akan menerima lapisan Paint baru segera dan kami dapat lebih langsung menghilangkan tag yang tidak diinginkan ini.

Ini tahun 2017, dan untuk Pertanyaan 2011 ini saya tidak suka salah satu jawabannya . Banyak regex, kelas besar, loadXML dll ...

Solusi mudah yang memecahkan masalah yang diketahui:

$dom = new DOMDocument();
$dom->loadHTML( ''.mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8').'' , LIBXML_HTML_NODEFDTD);
$html = substr(trim($dom->saveHTML()),12,-14);

Mudah, Sederhana, Solid, Cepat. Kode ini akan berfungsi mengenai tag HTML dan penyandian seperti:

$html = '

äöü

ß

';

Jika ada yang menemukan kesalahan, tolong katakan, saya akan menggunakan ini sendiri.

Edit , Opsi valid lain yang berfungsi tanpa kesalahan (sangat mirip dengan yang sudah diberikan):

@$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$saved_dom = trim($dom->saveHTML());
$start_dom = stripos($saved_dom,'')+6;
$html = substr($saved_dom,$start_dom,strripos($saved_dom,'') - $start_dom );

Anda bisa menambahkan tubuh sendiri untuk mencegah hal aneh pada bulunya.

Opsi ketiga:

 $mock = new DOMDocument;
 $body = $dom->getElementsByTagName('body')->item(0);
  foreach ($body->childNodes as $child){
     $mock->appendChild($mock->importNode($child, true));
  }
$html = trim($mock->saveHTML());

Gunakan fungsi ini

$layout = preg_replace('~<(?:!DOCTYPE|/?(?:html|head|body))[^>]*>\s*~i', '', $layout);

Oke saya menemukan solusi yang lebih elegan, tapi itu membosankan:

$d = new DOMDocument();
@$d->loadHTML($yourcontent);
...
// do your manipulation, processing, etc of it blah blah blah
...
// then to save, do this
$x = new DOMXPath($d);
$everything = $x->query("body/*"); // retrieves all elements inside body tag
if ($everything->length > 0) { // check if it retrieved anything in there
      $output = '';
      foreach ($everything as $thing) {
           $output .= $d->saveXML($thing);
      }
      echo $output; // voila, no more annoying html wrappers or body tag
}

Baiklah, semoga ini tidak menghilangkan apa pun dan membantu seseorang?

Tidak ada solusi lain pada saat penulisan ini (Juni, 2012) yang dapat sepenuhnya memenuhi kebutuhan saya, jadi saya menulis solusi yang menangani kasus-kasus berikut: 

  • Menerima konten teks biasa yang tidak memiliki tag, serta konten HTML.
  • Tidak menambahkan tag apa pun (termasuk , , , , dan tag

    )

  • Meninggalkan apa pun yang dibungkus

    sendirian.

  • Meninggalkan teks kosong saja.

Jadi, inilah solusi yang memperbaiki masalah tersebut:

class DOMDocumentWorkaround
{
    /**
     * Convert a string which may have HTML components into a DOMDocument instance.
     *
     * @param string $html - The HTML text to turn into a string.
     * @return \DOMDocument - A DOMDocument created from the given html.
     */
    public static function getDomDocumentFromHtml($html)
    {
        $domDocument = new DOMDocument();

        // Wrap the HTML in 
tags because loadXML expects everything to be within some kind of tag. // LIBXML_NOERROR and LIBXML_NOWARNING mean this will fail silently and return an empty DOMDocument if it fails. $domDocument->loadXML('
' . $html . '
', LIBXML_NOERROR | LIBXML_NOWARNING); return $domDocument; } /** * Convert a DOMDocument back into an HTML string, which is reasonably close to what we started with. * * @param \DOMDocument $domDocument * @return string - The resulting HTML string */ public static function getHtmlFromDomDocument($domDocument) { // Convert the DOMDocument back to a string. $xml = $domDocument->saveXML(); // Strip out the XML declaration, if one exists $xmlDeclaration = "\n"; if (substr($xml, 0, strlen($xmlDeclaration)) == $xmlDeclaration) { $xml = substr($xml, strlen($xmlDeclaration)); } // If the original HTML was empty, loadXML collapses our
into
. Remove it. if ($xml == "
\n") { $xml = ''; } else { // Remove the opening
tag we previously added, if it exists. $openDivTag = "
"; if (substr($xml, 0, strlen($openDivTag)) == $openDivTag) { $xml = substr($xml, strlen($openDivTag)); } // Remove the closing
tag we previously added, if it exists. $closeDivTag = "
\n"; $closeChunk = substr($xml, -strlen($closeDivTag)); if ($closeChunk == $closeDivTag) { $xml = substr($xml, 0, -strlen($closeDivTag)); } } return $xml; } }

Saya juga menulis beberapa tes yang akan hidup di kelas yang sama:

public static function testHtmlToDomConversions($content)
{
    // test that converting the $content to a DOMDocument and back does not change the HTML
    if ($content !== self::getHtmlFromDomDocument(self::getDomDocumentFromHtml($content))) {
        echo "Failed\n";
    }
    else {
        echo "Succeeded\n";
    }
}

public static function testAll()
{
    self::testHtmlToDomConversions('

Here is some sample text

'); self::testHtmlToDomConversions('
Lots of
nested
divs
'); self::testHtmlToDomConversions('Normal Text'); self::testHtmlToDomConversions(''); //empty }

Anda dapat memeriksa apakah itu berfungsi untuk Anda sendiri. DomDocumentWorkaround::testAll() mengembalikan ini:

    Succeeded
    Succeeded
    Succeeded
    Succeeded

Menambahkan tag akan memicu perilaku memperbaiki DOMDocument. Bagian baiknya adalah Anda tidak perlu menambahkan tag itu sama sekali. Jika Anda tidak ingin menggunakan pengkodean pilihan Anda, sampaikan saja sebagai argumen konstruktor.

http://php.net/manual/en/domdocument.construct.php

$doc = new DOMDocument('1.0', 'UTF-8');
$node = $doc->createElement('div', 'Hello World');
$doc->appendChild($node);
echo $doc->saveHTML();

Keluaran

Hello World

Terima kasih kepada @Bart

Saya memiliki persyaratan ini juga, dan menyukai solusi yang diposting oleh Alex di atas. Namun ada beberapa masalah - jika elemen mengandung lebih dari satu elemen child, dokumen yang dihasilkan hanya akan berisi elemen child pertama dari , tidak semuanya. Juga, saya membutuhkan pengupasan untuk menangani berbagai hal secara kondisional - hanya ketika Anda memiliki dokumen dengan judul HTML. Jadi saya memperbaikinya sebagai berikut. Alih-alih menghapus , saya mengubahnya menjadi

, dan menghapus deklarasi XML dan .

function strip_html_headings($html_doc)
{
    if (is_null($html_doc))
    {
        // might be better to issue an exception, but we silently return
        return;
    }

    // remove firstChild) &&
        $html_doc->firstChild->nodeType == XML_DOCUMENT_TYPE_NODE)
    {
        $html_doc->removeChild($html_doc->firstChild);     
    }

    if (!is_null($html_doc->firstChild) &&
        strtolower($html_doc->firstChild->tagName) == 'html' &&
        !is_null($html_doc->firstChild->firstChild) &&
        strtolower($html_doc->firstChild->firstChild->tagName) == 'body')
    {
        // we have 'html/body' - replace both nodes with a single "div"        
        $div_node = $html_doc->createElement('div');

        // copy all the child nodes of 'body' to 'div'
        foreach ($html_doc->firstChild->firstChild->childNodes as $child)
        {
            // deep copies each child node, with attributes
            $child = $html_doc->importNode($child, true);
            // adds node to 'div''
            $div_node->appendChild($child);
        }

        // replace 'html/body' with 'div'
        $html_doc->removeChild($html_doc->firstChild);
        $html_doc->appendChild($div_node);
    }
}

Saya memiliki PHP 5.3 dan jawaban di sini tidak bekerja untuk saya.

$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild); mengganti semua dokumen dengan hanya anak pertama, saya memiliki banyak paragraf dan hanya yang pertama diselamatkan, tetapi solusinya memberi saya titik awal yang baik untuk menulis sesuatu tanpa regex Saya meninggalkan beberapa komentar dan saya cukup yakin ini dapat ditingkatkan tetapi jika seseorang memiliki masalah yang sama dengan saya, itu bisa menjadi titik awal yang baik.

function extractDOMContent($doc){
    # remove removeChild($doc->doctype);

    // lets get all children inside the body tag
    foreach ($doc->firstChild->firstChild->childNodes as $k => $v) {
        if($k !== 0){ // don't store the first element since that one will be used to replace the html tag
            $doc->appendChild( clone($v) ); // appending element to the root so we can remove the first element and still have all the others
        }
    }
    // replace the body tag with the first children
    $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
    return $doc;
}

Maka kita bisa menggunakannya seperti ini:

$doc = new DOMDocument();
$doc->encoding = 'UTF-8';
$doc->loadHTML('

Some html here

And more html

and some html

'); $doc = extractDOMContent($doc);

Perhatikan bahwa appendChild menerima DOMNode jadi kita tidak perlu membuat elemen baru, kita bisa menggunakan kembali yang sudah ada yang mengimplementasikan DOMNodesuch sebagai DOMElement ini penting untuk menjaga kode "waras" ketika memanipulasi banyak dokumen HTML/XML

Saya menemukan topik ini untuk menemukan cara menghapus pembungkus HTML. Menggunakan LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD berfungsi baik, tapi saya punya masalah dengan utf-8. Setelah banyak usaha saya menemukan solusi. Saya mempostingnya di bawah ini bagi siapa saja yang memiliki masalah yang sama.

Masalah yang disebabkan karena

Masalah:

$dom = new DOMDocument();
$dom->loadHTML('' . $document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->saveHTML();

Solusi 1:

$dom->loadHTML(mb_convert_encoding($document, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $dom->saveHTML($dom->documentElement));

Solusi 2:

$dom->loadHTML($document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
utf8_decode($dom->saveHTML($dom->documentElement));

Jika solusi flag dijawab oleh Alessandro Vendruscolo tidak berfungsi, Anda dapat mencoba ini:

$dom = new DOMDocument();
$dom->loadHTML($content);

//do your stuff..

$finalHtml = '';
$bodyTag = $dom->documentElement->getElementsByTagName('body')->item(0);
foreach ($bodyTag->childNodes as $rootLevelTag) {
    $finalHtml .= $dom->saveHTML($rootLevelTag);
}
echo $finalHtml;

$bodyTag akan berisi kode HTML lengkap Anda yang diproses tanpa semua bungkus HTML itu, kecuali untuk tag , yang merupakan akar dari konten Anda. Kemudian Anda dapat menggunakan fungsi regex atau trim untuk menghapusnya dari string terakhir (setelah saveHTML) atau, seperti dalam kasus di atas, iterate semua childen-nya, menyimpan konten mereka ke dalam variabel sementara $finalHtml dan mengembalikannya (apa yang saya percaya lebih aman).

Saya menemukan masalah ini juga.

Sayangnya, saya merasa tidak nyaman menggunakan salah satu solusi yang disediakan di utas ini, jadi saya pergi untuk memeriksa yang akan memuaskan saya.

Inilah yang saya hasilkan dan bekerja tanpa masalah:

$domxpath = new \DOMXPath($domDocument);

/** @var \DOMNodeList $subset */
$subset = $domxpath->query('descendant-or-self::body/*');

$html = '';
foreach ($subset as $domElement) {
    /** @var $domElement \DOMElement */
    $html .= $domDocument->saveHTML($domElement);
}

Pada dasarnya ini bekerja dengan cara yang mirip dengan sebagian besar solusi yang disediakan di sini, tetapi alih-alih melakukan pekerjaan manual, ia menggunakan pemilih xpath untuk memilih semua elemen dalam tubuh dan menggabungkan kode html mereka.

server saya mendapat php 5.3 dan tidak dapat memutakhirkan opsi tersebut

LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD

bukan untuk saya.

Untuk mengatasi ini saya katakan ke Fungsi SaveXML untuk mencetak elemen Tubuh dan kemudian hanya mengganti "tubuh" dengan "div"

ini kode saya, semoga membantu seseorang:

loadHTML(''.$html);
$tabContentDomDoc->encoding = 'UTF-8';
$tabContentDomDocBody = $tabContentDomDoc->getElementsByTagName('body')->item(0);
if(is_object($tabContentDomDocBody)){
    echo (str_replace("body","div",$tabContentDomDoc->saveXML($tabContentDomDocBody)));
}
?>

utf-8 adalah untuk dukungan bahasa Ibrani.

Jawaban Alex benar, tetapi dapat menyebabkan kesalahan berikut pada node kosong:

Argumen 1 yang diteruskan ke DOMNode :: removeChild () harus berupa instance dari__ DOMNode

Ini dia mod kecilku:

    $output = '';
    $doc = new DOMDocument();
    $doc->loadHTML($htmlString); //feed with html here

    if (isset($doc->firstChild)) {

        /* remove doctype */

        $doc->removeChild($doc->firstChild);

        /* remove html and body */

        if (isset($doc->firstChild->firstChild->firstChild)) {
            $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
            $output = trim($doc->saveHTML());
        }
    }
    return $output;

Menambahkan trim () juga merupakan ide bagus untuk menghapus spasi putih.

Bagi siapa pun yang menggunakan Drupal, ada fungsi bawaan untuk melakukan ini: 

https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x

Kode untuk referensi:

function filter_dom_serialize($dom_document) {
  $body_node = $dom_document->getElementsByTagName('body')->item(0);
  $body_content = '';

  if ($body_node !== NULL) {
    foreach ($body_node->getElementsByTagName('script') as $node) {
      filter_dom_serialize_escape_cdata_element($dom_document, $node);
    }

    foreach ($body_node->getElementsByTagName('style') as $node) {
      filter_dom_serialize_escape_cdata_element($dom_document, $node, '/*', '*/');
    }

    foreach ($body_node->childNodes as $child_node) {
      $body_content .= $dom_document->saveXML($child_node);
    }
    return preg_replace('|<([^> ]*)/>|i', '<$1 />', $body_content);
  }
  else {
    return $body_content;
  }
}

Saya berjuang dengan ini di RHEL7 menjalankan PHP 5.6.25 dan LibXML 2.9. (Barang lama di tahun 2018, saya tahu, tapi itu Red Hat untuk Anda.)

Saya telah menemukan bahwa banyak solusi yang disarankan oleh Alessandro Vendruscolo memecah HTML dengan mengatur ulang tag. Yaitu.:

First.

Second.

'

menjadi:

First.

Second.

'

Ini berlaku untuk kedua opsi yang ia sarankan Anda gunakan: LIBXML_HTML_NOIMPLIED dan LIBXML_HTML_NODEFDTD.

Solusi yang disarankan oleh Alex berjalan setengah jalan untuk menyelesaikannya, tetapi tidak berfungsi jika memiliki lebih dari satu simpul anak.

Solusi yang bekerja untuk saya adalah sebagai berikut:

Pertama, untuk memuat DOMDocument, saya menggunakan:

$doc = new DOMDocument()
$doc->loadHTML($content);

Untuk menyimpan dokumen setelah memijat Dokumen DOM, saya menggunakan:

// remove removeChild($doc->doctype);  
$content = $doc->saveHTML();
// remove  
$content = str_replace('', '', $content);
$content = str_replace('', '', $content);

Saya orang pertama yang setuju bahwa ini bukan solusi yang sangat elegan - tetapi berhasil.

Saya mungkin terlambat. Tapi mungkin seseorang (seperti saya) masih memiliki masalah ini.
Jadi, tidak ada yang berhasil bagi saya. Karena $ dom-> loadHTML juga menutup tag terbuka, tidak hanya menambahkan tag html dan tubuh.
Jadi, tambahkan elemen

tidak berfungsi untuk saya, karena saya kadang-kadang suka 3-4 div tertutup di bagian html.
.__ Solusi saya:

1.) Tambahkan marker untuk dipotong, lalu muat html

$html_piece = "[MARK]".$html_piece."[/MARK]";
$dom->loadHTML($html_piece);

2.) lakukan apa pun yang Anda inginkan dengan dokumen tersebut
3.) Simpan html

$new_html_piece = $dom->saveHTML();

4.) sebelum Anda mengembalikannya, hapus tag

dari marker, anehnya itu hanya muncul di [MARK] tetapi tidak di [/ MARK] ...!?

$new_html_piece = preg_replace( "/]*?>(\[MARK\]|\s)*?<\/p>/", "[MARK]" , $new_html_piece );

5.) hapus semuanya sebelum dan sesudah penanda

$pattern_contents = '{\[MARK\](.*?)\[\/MARK\]}is';
if (preg_match($pattern_contents, $new_html_piece, $matches)) {
    $new_html_piece = $matches[1];
}

6.) kembalikan

return $new_html_piece;

Akan jauh lebih mudah jika LIBXML_HTML_NOIMPLIED bekerja untuk saya. Itu bisa, tetapi tidak. PHP 5.4.17, libxml Versi 2.7.8. 
Saya merasa sangat aneh, saya menggunakan parser HTML DOM dan kemudian, untuk memperbaiki "hal" ini saya harus menggunakan regex ... Intinya adalah, tidak menggunakan regex;)