Come ottenere innerHTML di DOMNode?


96

Quale funzione usi per ottenere innerHTML di un dato DOMNode nell'implementazione PHP DOM? Qualcuno può dare una soluzione affidabile?

Ovviamente lo farà anche outerHTML.

Risposte:


152

Confronta questa variante aggiornata con la nota utente del manuale PHP n. 89718 :

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

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

    return $innerHTML; 
} 
?> 

Esempio:

<?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); 
} 
?> 

Grazie. Funziona bene. Non dovrebbe $ dom-> preservareWhiteSpace = false; essere prima del caricamento del documento?
Dawid Ohia

@ JohnM2: Sì, dovrebbe .
hakre

Note aggiuntive: a partire da PHP 5.3.6 puoi risparmiare il file temporaneo DOMDocument. Inoltre si potrebbe voler sostituire il trimcon un ltrim(o addirittura rimuoverlo completamente) per preservare un po 'di spazio bianco come le interruzioni di riga.
hakre

Una funzione come questa dovrebbe essere aggiunta alla classe DomDocument.
Nate

3
Ho dovuto modificare la dichiarazione della funzione per aspettarmi a DOMElementinvece di a DOMNodementre stavo passando il ritorno da DOMDocument::getElementById(). Nel caso in cui inciampi qualcun altro.
miken32

25

Ecco una versione in uno stile di programmazione funzionale :

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

13

Per restituire il valore htmldi un elemento, puoi usare C14N () :

$dom = new DOMDocument();
$dom->loadHtml($html);
$x = new DOMXpath($dom);
foreach($x->query('//table') as $table){
    echo $table->C14N();
}

2
C14N tenterà di convertire l'HTML in un XML valido. Ad esempio, diventerà <br> </br>
ajaybc

È un modo sporco di scaricare l'HTML dell'elemento, senza dover usare saveHTML che produrrà tag html, head e body.
CONvid19

9

Una versione semplificata della risposta di Haim Evgi:

<?php

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

    $html = '';

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

    return $html;
}

Utilizzo di esempio:

<?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>
*/

Non è necessario impostare preserveWhiteSpaceo formatOutput.


4

Oltre alla bella versione di trincot con array_mape implodema questa volta con array_reduce:

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

Ancora non capisco, perché non esiste un reduce()metodo che accetti array e iteratori allo stesso modo.


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);
  }
}

2

Ecco un altro approccio basato su questo commento di Drupella su php.net, che ha funzionato bene per il mio progetto. Definisce il innerHTML()creando un nuovoDOMDocument , importando e aggiungendo ad esso il nodo di destinazione, invece di iterare esplicitamente sui nodi figli.

InnerHTML

Definiamo questa funzione di supporto:

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 );
}

dove possiamo includere / escludere il tag di destinazione esterno tramite il secondo argomento di input.

Esempio di utilizzo

Qui estraiamo l'HTML interno per un tag di destinazione dato dall'attributo id "first":

$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>
}

Esempio dal vivo:

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


1

Vecchia query, ma esiste un metodo integrato per farlo. Basta passare il nodo di destinazione a DomDocument->saveHtml().

Esempio completo:

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

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


Avviso: DOMDocument :: saveHTML () prevede che il parametro 1 sia DOMNode, oggetto fornito
Ivan Gusev,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.