Bagaimana cara mendapatkan innerHTML dari DOMNode?

96

Fungsi apa yang Anda gunakan untuk mendapatkan innerHTML dari DOMNode tertentu dalam implementasi PHP DOM? Bisakah seseorang memberikan solusi yang andal?

Tentu saja outerHTML juga bisa.

Dawid Ohia
sumber

Jawaban:

152

Bandingkan varian yang diperbarui ini dengan Catatan Pengguna Manual PHP # 89718 :

<?php 
function DOMinnerHTML(DOMNode $element) 
{ 
    $innerHTML = ""; 
    $children  = $element->childNodes;

    foreach ($children as $child) 
    { 
        $innerHTML .= $element->ownerDocument->saveHTML($child);
    }

    return $innerHTML; 
} 
?> 

Contoh:

<?php 
$dom= new DOMDocument(); 
$dom->preserveWhiteSpace = false;
$dom->formatOutput       = true;
$dom->load($html_string); 

$domTables = $dom->getElementsByTagName("table"); 

// Iterate over DOMNodeList (Implements Traversable)
foreach ($domTables as $table) 
{ 
    echo DOMinnerHTML($table); 
} 
?> 
Haim Evgi
sumber
Terima kasih. Ini bekerja dengan baik. Seharusnya $ dom-> preservWhiteSpace = false; sebelum dokumen dimuat?
Dawid Ohia
@ JohnM2: Ya, seharusnya .
hakre
Catatan tambahan: Sejak PHP 5.3.6 Anda dapat menyimpan sementara DOMDocument. Juga seseorang mungkin ingin mengganti trimdengan ltrim(atau bahkan menghapusnya sepenuhnya) untuk mempertahankan sedikit spasi seperti jeda baris.
hakre
Fungsi seperti ini harus ditambahkan ke kelas DomDocument.
Nate
3
Saya harus mengubah deklarasi fungsi untuk mengharapkan a DOMElementalih - alih a DOMNodesaat saya meneruskan pengembalian DOMDocument::getElementById(). Kalau-kalau itu membuat orang lain tersandung.
miken32
25

Berikut adalah versi dalam gaya pemrograman fungsional :

function innerHTML($node) {
    return implode(array_map([$node->ownerDocument,"saveHTML"], 
                             iterator_to_array($node->childNodes)));
}
trincot
sumber
13

Untuk mengembalikan htmlelemen, Anda bisa menggunakan C14N () :

$dom = new DOMDocument();
$dom->loadHtml($html);
$x = new DOMXpath($dom);
foreach($x->query('//table') as $table){
    echo $table->C14N();
}
CONvid19
sumber
2
C14N akan mencoba untuk mengubah HTML menjadi XML yang valid. Misalnya <br> akan menjadi <br> </br>
ajaybc
Ini adalah cara kotor untuk membuang HTML elemen, tanpa harus menggunakan saveHTML yang akan mengeluarkan tag html, head dan body.
CONvid19
9

Versi sederhana dari jawaban Haim Evgi:

<?php

function innerHTML(\DOMElement $element)
{
    $doc = $element->ownerDocument;

    $html = '';

    foreach ($element->childNodes as $node) {
        $html .= $doc->saveHTML($node);
    }

    return $html;
}

Contoh penggunaan:

<?php

$doc = new \DOMDocument();
$doc->loadHTML("<body><div id='foo'><p>This is <b>an <i>example</i></b> paragraph<br>\n\ncontaining newlines.</p><p>This is another paragraph.</p></div></body>");

print innerHTML($doc->getElementById('foo'));

/*
<p>This is <b>an <i>example</i></b> paragraph<br>

containing newlines.</p>
<p>This is another paragraph.</p>
*/

Tidak perlu mengatur preserveWhiteSpaceatau formatOutput.

Alf Eaton
sumber
4

Selain versi trincot yang bagus dengan array_mapdan implodetapi kali ini dengan array_reduce:

return array_reduce(
   iterator_to_array($node->childNodes),
   function ($carry, \DOMNode $child) {
        return $carry.$child->ownerDocument->saveHTML($child);
   }
);

Masih belum mengerti, mengapa tidak ada reduce()metode yang menerima array dan iterator sama.

flu
sumber
3
function setnodevalue($doc, $node, $newvalue){
  while($node->childNodes->length> 0){
    $node->removeChild($node->firstChild);
  }
  $fragment= $doc->createDocumentFragment();
  $fragment->preserveWhiteSpace= false;
  if(!empty($newvalue)){
    $fragment->appendXML(trim($newvalue));
    $nod= $doc->importNode($fragment, true);
    $node->appendChild($nod);
  }
}
Chris
sumber
2

Berikut pendekatan lain berdasarkan komentar ini oleh Drupella di php.net, yang bekerja dengan baik untuk proyek saya. Ini mendefinisikan innerHTML()dengan membuat yang baruDOMDocument , mengimpor dan menambahkan ke node target, bukannya secara eksplisit melakukan iterasi pada node turunan.

InnerHTML

Mari kita definisikan fungsi pembantu ini:

function innerHTML( \DOMNode $n, $include_target_tag = true ) {
  $doc = new \DOMDocument();
  $doc->appendChild( $doc->importNode( $n, true ) );
  $html = trim( $doc->saveHTML() );
  if ( $include_target_tag ) {
      return $html;
  }
  return preg_replace( '@^<' . $n->nodeName .'[^>]*>|</'. $n->nodeName .'>$@', '', $html );
}

di mana kita dapat menyertakan / mengecualikan tag target luar melalui argumen masukan kedua.

Contoh Penggunaan

Di sini kami mengekstrak HTML bagian dalam untuk tag target yang diberikan oleh atribut id "pertama":

$html = '<div id="first"><h1>Hello</h1></div><div id="second"><p>World!</p></div>';
$doc  = new \DOMDocument();
$doc->loadHTML( $html );
$node = $doc->getElementById( 'first' );

if ( $node instanceof \DOMNode ) {

    echo innerHTML( $node, true );
    // Output: <div id="first"><h1>Hello</h1></div>    

    echo innerHTML( $node, false );
    // Output: <h1>Hello</h1>
}

Contoh langsung:

http://sandbox.onlinephpfunctions.com/code/2714ea116aad9957c3c437d46134a1688e9133b8

birgire
sumber
1

Kueri lama, tetapi ada metode bawaan untuk melakukannya. Cukup teruskan node target ke DomDocument->saveHtml().

Contoh lengkap:

$html = '<div><p>ciao questa è una <b>prova</b>.</p></div>';
$dom = new DomDocument($html);
@$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$node = $xpath->query('.//div/*'); // with * you get inner html without surrounding div tag; without * you get inner html with surrounding div tag
$innerHtml = $dom->saveHtml($node);
var_dump($innerHtml);

Keluaran: <p>ciao questa è una <b>prova</b>.</p>

Marco Marsala
sumber
Peringatan: DOMDocument :: saveHTML () mengharapkan parameter 1 menjadi DOMNode, objek diberikan
Ivan Gusev