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.

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

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

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

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.


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.


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

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


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>


Attention: DOMDocument :: saveHTML () s'attend à ce que le paramètre 1 soit DOMNode, objet donné
Ivan Gusev
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.