Comment obtenir innerHTML de DOMNode?

96

Quelle fonction utilisez-vous pour obtenir innerHTML d'un DOMNode donné dans l'implémentation PHP DOM? Quelqu'un peut-il donner une solution fiable?

Bien sûr, externalHTML fera également l'affaire.

Dawid Ohia
la source

Réponses:

152

Comparez cette variante mise à jour avec PHP Manual User Note # 89718 :

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

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

    return $innerHTML; 
} 
?> 

Exemple:

<?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
la source
Merci. Ça fonctionne bien. Ne devrait pas $ dom-> preserveWhiteSpace = false; être avant le chargement du document?
Dawid Ohia
@ JohnM2: Oui, ça devrait .
hakre
Notes supplémentaires: Depuis PHP 5.3.6, vous pouvez épargner le fichier temporaire DOMDocument. On peut également vouloir remplacer le trimpar un ltrim(ou même le supprimer complètement) pour conserver un peu d'espace blanc comme les sauts de ligne.
hakre
Une fonction comme celle-ci doit être ajoutée à la classe DomDocument.
Nate
3
J'ai dû changer la déclaration de fonction pour attendre un DOMElementau lieu d'un DOMNodecomme je passais le retour DOMDocument::getElementById(). Juste au cas où ça ferait trébucher quelqu'un d'autre.
miken32
25

Voici une version dans un style de programmation fonctionnelle :

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

Pour renvoyer le htmld'un élément, vous pouvez utiliser C14N () :

$dom = new DOMDocument();
$dom->loadHtml($html);
$x = new DOMXpath($dom);
foreach($x->query('//table') as $table){
    echo $table->C14N();
}
CONvid19
la source
2
C14N tentera de convertir le HTML en un XML valide. Par exemple, <br> deviendra <br> </br>
ajaybc
C'est une manière sale de vider le HTML de l'élément, sans avoir à utiliser saveHTML qui produira des balises html, head et body.
CONvid19
9

Une version simplifiée de la réponse de Haim Evgi:

<?php

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

    $html = '';

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

    return $html;
}

Exemple d'utilisation:

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

Il n'est pas nécessaire de définir preserveWhiteSpaceou formatOutput.

Alf Eaton
la source
4

En plus de la belle version de trincot avec array_mapet implodemais cette fois avec array_reduce:

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

Je ne comprends toujours pas pourquoi il n'y a pas de reduce()méthode qui accepte les tableaux et les itérateurs.

grippe
la source
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
la source
2

Voici une autre approche basée sur ce commentaire de Drupella sur php.net, qui a bien fonctionné pour mon projet. Il définit le innerHTML()en créant un nouveau DOMDocument, en important et en y ajoutant le nœud cible, au lieu d'itérer explicitement sur les nœuds enfants.

InnerHTML

Définissons cette fonction d'assistance:

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

où nous pouvons inclure / exclure la balise cible externe via le deuxième argument d'entrée.

Exemple d'utilisation

Ici, nous extrayons le HTML interne d'une balise cible donnée par le "premier" attribut id:

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

Exemple en direct:

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

Birgire
la source
1

Ancienne requête, mais il existe une méthode intégrée pour le faire. Passez simplement le nœud cible à DomDocument->saveHtml().

Exemple complet:

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

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

Marco Marsala
la source
Attention: DOMDocument :: saveHTML () s'attend à ce que le paramètre 1 soit DOMNode, objet donné
Ivan Gusev