¿Cómo obtener innerHTML de DOMNode?


96

¿Qué función usa para obtener innerHTML de un DOMNode dado en la implementación PHP DOM? ¿Alguien puede dar una solución confiable?

Por supuesto, el HTML externo también lo hará.

Respuestas:


152

Compare esta variante actualizada con la nota de usuario del manual PHP # 89718 :

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

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

    return $innerHTML; 
} 
?> 

Ejemplo:

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

Gracias. Funciona bien. No debería $ dom-> preserveWhiteSpace = false; estar antes de la carga del documento?
Dawid Ohia

@ JohnM2: Sí, debería .
hakre

Notas adicionales: Desde PHP 5.3.6 puede ahorrar el archivo temporal DOMDocument. También es posible que desee reemplazar el trimcon un ltrim(o incluso eliminarlo por completo) para preservar un poco del espacio en blanco como saltos de línea.
hakre

Una función como esta debería agregarse a la clase DomDocument.
Nate

3
Tuve que cambiar la declaración de la función para esperar un en DOMElementlugar de un DOMNodecomo estaba pasando el retorno DOMDocument::getElementById(). Por si acaso tropieza con alguien más.
miken32

25

Aquí hay una versión en un estilo de programación funcional :

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

13

Para devolver el htmlde un elemento, puede usar C14N () :

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

2
C14N intentará convertir el HTML a un XML válido. Por ejemplo, <br> se convertirá en <br> </br>
ajaybc

Es una forma sucia de volcar el HTML del elemento, sin tener que usar saveHTML que generará etiquetas html, head y body.
CONvid19

9

Una versión simplificada de la respuesta de Haim Evgi:

<?php

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

    $html = '';

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

    return $html;
}

Uso de ejemplo:

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

No es necesario configurar preserveWhiteSpaceo formatOutput.


4

Además de la bonita versión de trincot con array_mapy implodepero esta vez con array_reduce:

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

Todavía no entiendo por qué no hay un reduce()método que acepte matrices e iteradores por igual.


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

Aquí hay otro enfoque basado en este comentario de Drupella en php.net, que funcionó bien para mi proyecto. Define el innerHTML()al crear un nuevo DOMDocument, importar y agregarle el nodo de destino, en lugar de iterar explícitamente sobre los nodos secundarios.

InnerHTML

Definamos esta función auxiliar:

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

donde podemos incluir / excluir la etiqueta de destino externa a través del segundo argumento de entrada.

Ejemplo de uso

Aquí extraemos el HTML interno para una etiqueta de destino dada por el atributo de identificación "primer":

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

Ejemplo en vivo:

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


1

Consulta antigua, pero hay un método integrado para hacerlo. Simplemente pase el nodo de destino a DomDocument->saveHtml().

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

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


Advertencia: DOMDocument :: saveHTML () espera que el parámetro 1 sea DOMNode, objeto dado
Ivan Gusev
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.